#include <sys/types.h>
#include <unistd.h>
#include <string.h>
-
+#include <dirent.h>
+
#include "v3_ctrl.h"
+#define SYS_PATH "/sys/devices/system/memory/"
-int main(int argc, char* argv[]) {
- unsigned long long base_addr = atoll(argv[1]);
- unsigned long long num_bytes = atoll(argv[2]);
- int v3_fd = 0;
- struct v3_mem_region mem;
+#define BUF_SIZE 128
- if (argc <= 2) {
- printf("Usage: ./v3_mem <base_addr> <num_bytes>\n");
- return -1;
+int dir_filter(const struct dirent * dir) {
+ if (strncmp("memory", dir->d_name, 6) == 0) {
+ return 1;
}
- printf("Giving Palacios %dMB of memory: \n", num_bytes / (1024 * 1024));
+ return 0;
+}
+
+
+
+int dir_cmp(const void * d1, const void * d2) {
+ const struct dirent ** dir1 = (const struct dirent **)d1;
+ const struct dirent ** dir2 = (const struct dirent **)d2;
+ int num1 = atoi((*dir1)->d_name + 6);
+ int num2 = atoi((*dir2)->d_name + 6);
+
+ return num1 - num2;
+}
- mem.base_addr = base_addr;
- mem.num_pages = num_bytes / 4096;
- v3_fd = open(v3_dev, O_RDONLY);
- if (v3_fd == -1) {
- printf("Error opening V3Vee control device\n");
+int main(int argc, char * argv[]) {
+ unsigned long long mem_size_bytes = 0;
+ unsigned int block_size_bytes = 0;
+ int bitmap_entries = 0;
+ unsigned char * bitmap = NULL;
+ int num_blocks = 0;
+ int reg_start = 0;
+
+
+ if (argc != 2) {
+ printf("Usage: v3_mem <memory size (MB)>\n");
return -1;
}
- ioctl(v3_fd, V3_ADD_MEMORY, &mem);
+ mem_size_bytes = atoll(argv[1]) * (1024 * 1024);
+ printf("Trying to find %dMB (%d bytes) of memory\n", atoll(argv[1]), mem_size_bytes);
- /* Close the file descriptor. */
- close(v3_fd);
-
+ /* Figure out the block size */
+ {
+ int tmp_fd = 0;
+ char tmp_buf[BUF_SIZE];
+ tmp_fd = open(SYS_PATH "block_size_bytes", O_RDONLY);
- return 0;
-}
+ if (tmp_fd == -1) {
+ perror("Could not open block size file: " SYS_PATH "block_size_bytes");
+ return -1;
+ }
+
+ if (read(tmp_fd, tmp_buf, BUF_SIZE) <= 0) {
+ perror("Could not read block size file: " SYS_PATH "block_size_bytes");
+ return -1;
+ }
+
+ close(tmp_fd);
+ block_size_bytes = strtoll(tmp_buf, NULL, 16);
+ printf("Memory block size is %dMB (%d bytes)\n", block_size_bytes / (1024 * 1024), block_size_bytes);
+ }
+
-int read_file(int fd, int size, unsigned char * buf) {
- int left_to_read = size;
- int have_read = 0;
+ num_blocks = mem_size_bytes / block_size_bytes;
+ if (block_size_bytes % mem_size_bytes) num_blocks++;
- while (left_to_read != 0) {
- int bytes_read = read(fd, buf + have_read, left_to_read);
+ printf("Looking for %d blocks of memory\n", num_blocks);
- if (bytes_read <= 0) {
- break;
+
+ // We now need to find <num_blocks> consecutive offlinable memory blocks
+
+ /* Scan the memory directories */
+ {
+ struct dirent ** namelist = NULL;
+ int size = 0;
+ int i = 0;
+
+ bitmap_entries = scandir(SYS_PATH, &namelist, dir_filter, dir_cmp);
+
+ size = bitmap_entries / 8;
+ if (bitmap_entries % 8) size++;
+
+ bitmap = malloc(size);
+ memset(bitmap, 0, size);
+
+ for (i = 0; i < bitmap_entries; i++) {
+ struct dirent * tmp_dir = namelist[i];
+ int major = i / 8;
+ int minor = i % 8;
+ int block_fd = 0;
+ char status_str[BUF_SIZE];
+ char fname[BUF_SIZE];
+
+ memset(status_str, 0, BUF_SIZE);
+ memset(fname, 0, BUF_SIZE);
+
+ snprintf(fname, BUF_SIZE, "%s%s/removable", SYS_PATH, tmp_dir->d_name);
+
+ printf("Checking %s...", fname);
+
+ block_fd = open(fname, O_RDONLY);
+
+ if (block_fd == -1) {
+ printf("Hotpluggable memory not supported...\n");
+ return -1;
+ }
+
+ if (read(block_fd, status_str, BUF_SIZE) <= 0) {
+ perror("Could not read block status");
+ return -1;
+ }
+
+ close(block_fd);
+
+ if (atoi(status_str) == 1) {
+ printf("Removable\n");
+ bitmap[major] |= (0x1 << minor);
+ } else {
+ printf("Not removable\n");
+ }
}
- have_read += bytes_read;
- left_to_read -= bytes_read;
}
+
- if (left_to_read != 0) {
- printf("Error could not finish reading file\n");
- return -1;
+ /* Scan bitmap for enough consecutive space */
+ {
+ // num_blocks: The number of blocks we need to find
+ // bitmap: bitmap of blocks (1 == allocatable)
+ // bitmap_entries: number of blocks in the system/number of bits in bitmap
+ // reg_start: The block index where our allocation will start
+
+ int i = 0;
+ int run_len = 0;
+
+ for (i = 0; i < bitmap_entries; i++) {
+ int i_major = i / 8;
+ int i_minor = i % 8;
+
+
+ if (!(bitmap[i_major] & (0x1 << i_minor))) {
+ reg_start = i + 1; // skip the region start to next entry
+ run_len = 0;
+ continue;
+ }
+
+ run_len++;
+
+ if (run_len >= num_blocks) {
+ break;
+ }
+ }
+
+ free(bitmap);
+
+ if (run_len < num_blocks) {
+ fprintf(stderr, "Could not find enough consecutive memory blocks... (found %d)\n", run_len);
+ return -1;
+ }
}
- return 0;
-}
+
+ /* Offline memory blocks starting at reg_start */
+ {
+ int i = 0;
+
+ for (i = 0; i < num_blocks; i++) {
+ FILE * block_file = NULL;
+ char fname[256];
+
+ memset(fname, 0, 256);
+
+ snprintf(fname, 256, "%smemory%d/state", SYS_PATH, i + reg_start);
+
+ block_file = fopen(fname, "r+");
+
+ if (block_file == NULL) {
+ perror("Could not open block file");
+ return -1;
+ }
+
+
+ printf("Offlining block %d (%s)\n", i + reg_start, fname);
+ fprintf(block_file, "offline\n");
+
+ fclose(block_file);
+ }
+ }
+
+
+ /* Memory is offlined. Calculate size and phys start addr to send to Palacios */
+
+ {
+ int v3_fd = 0;
+ struct v3_mem_region mem;
+ unsigned long long num_bytes = num_blocks * block_size_bytes;
+ unsigned long long base_addr = reg_start * block_size_bytes;
+
+ printf("Giving Palacios %dMB of memory at (%p) \n",
+ num_bytes / (1024 * 1024), base_addr);
+
+ mem.base_addr = base_addr;
+ mem.num_pages = num_bytes / 4096;
+
+ v3_fd = open(v3_dev, O_RDONLY);
+
+ if (v3_fd == -1) {
+ printf("Error opening V3Vee control device\n");
+ return -1;
+ }
+
+ ioctl(v3_fd, V3_ADD_MEMORY, &mem);
+
+ /* Close the file descriptor. */
+ close(v3_fd);
+ }
+
+ return 0;
+}