10 #include <sys/ioctl.h>
12 #include <sys/types.h>
19 #define SYS_PATH "/sys/devices/system/memory/"
26 static int offline_memory(unsigned long long mem_size_bytes,
27 unsigned long long mem_min_start,
29 unsigned long long *num_bytes,
30 unsigned long long *base_addr);
32 int main(int argc, char * argv[]) {
33 unsigned long long mem_size_bytes = 0;
34 unsigned long long mem_min_start = 0;
40 unsigned long long num_bytes, base_addr;
41 struct v3_mem_region mem;
43 if (argc<2 || argc>5) {
44 printf("usage: v3_mem [-r] [-l] [-n k] <memory size (MB)> [min_start (MB)]\n\n"
45 "Allocate memory for use by Palacios.\n\n"
46 "With -r this requests in-kernel allocation.\n"
47 "Without -r this attempts to offline memory via hot\n"
49 "With -l the request or offlining is limited to first 4 GB\n"
50 "Without -l the request or offlining has no limits\n\n"
51 "With -n k the request is for numa node k\n"
52 "Without -n k the request can be on any numa node\n\n"
53 "For offlining, min_start is the minimum allowable starting address.\n"
54 "This is zero by default\n\n");
58 while ((c=getopt(argc,argv,"rln:"))!=-1) {
71 printf("-n requires the numa node...\n");
73 printf("Unknown option %c\n",optopt);
77 printf("Unknown option %c\n",optopt);
83 mem_size_bytes = atoll(argv[optind]) * (1024 * 1024);
85 if ((optind+1) < argc) {
86 mem_min_start = atoll(argv[optind+1]) * (1024 * 1024);
89 v3_fd = open(v3_dev, O_RDONLY);
92 printf("Error opening V3Vee control device\n");
97 printf("Trying to offline memory (size=%llu, min_start=%llu, limit32=%d)\n",mem_size_bytes,mem_min_start,limit32);
98 if (offline_memory(mem_size_bytes,mem_min_start,limit32, &num_bytes, &base_addr)) {
99 printf("Could not offline memory\n");
102 mem.type=PREALLOCATED;
104 mem.base_addr=base_addr;
105 mem.num_pages=num_bytes/4096;
107 printf("Generating memory allocation request (size=%llu, limit32=%d)\n", mem_size_bytes, limit32);
108 mem.type = limit32 ? REQUESTED32 : REQUESTED;
110 num_bytes = mem_size_bytes;
114 if (ioctl(v3_fd, V3_ADD_MEMORY, &mem)<0) {
115 printf("Request rejected by Palacios\n");
119 printf("Request accepted by Palacios\n");
126 static int dir_filter(const struct dirent * dir) {
127 if (strncmp("memory", dir->d_name, 6) == 0) {
135 static int dir_cmp(const struct dirent **dir1, const struct dirent ** dir2) {
136 int num1 = atoi((*dir1)->d_name + 6);
137 int num2 = atoi((*dir2)->d_name + 6);
143 static int offline_memory(unsigned long long mem_size_bytes,
144 unsigned long long mem_min_start,
146 unsigned long long *num_bytes,
147 unsigned long long *base_addr)
150 unsigned int block_size_bytes = 0;
151 int bitmap_entries = 0;
152 unsigned char * bitmap = NULL;
158 printf("Trying to find %dMB (%d bytes) of memory above %llu with limit32=%d\n", mem_size_bytes/(1024*1024), mem_size_bytes, mem_min_start, limit32);
160 /* Figure out the block size */
163 char tmp_buf[BUF_SIZE];
165 tmp_fd = open(SYS_PATH "block_size_bytes", O_RDONLY);
168 perror("Could not open block size file: " SYS_PATH "block_size_bytes");
172 if (read(tmp_fd, tmp_buf, BUF_SIZE) <= 0) {
173 perror("Could not read block size file: " SYS_PATH "block_size_bytes");
179 block_size_bytes = strtoll(tmp_buf, NULL, 16);
181 printf("Memory block size is %dMB (%d bytes)\n", block_size_bytes / (1024 * 1024), block_size_bytes);
186 num_blocks = mem_size_bytes / block_size_bytes;
187 if (mem_size_bytes % block_size_bytes) num_blocks++;
189 mem_min_start = block_size_bytes *
190 ((mem_min_start / block_size_bytes) + (!!(mem_min_start % block_size_bytes)));
192 printf("Looking for %d blocks of memory starting at %p (block %llu) with limit32=%d\n", num_blocks, (void*)mem_min_start, mem_min_start/block_size_bytes,limit32);
195 // We now need to find <num_blocks> consecutive offlinable memory blocks
197 /* Scan the memory directories */
199 struct dirent ** namelist = NULL;
204 int first_block = mem_min_start/block_size_bytes;
205 int limit_block = 0xffffffff / block_size_bytes; // for 32 bit limiting
207 last_block = scandir(SYS_PATH, &namelist, dir_filter, dir_cmp);
208 bitmap_entries = atoi(namelist[last_block - 1]->d_name + 6) + 1;
210 size = bitmap_entries / 8;
211 if (bitmap_entries % 8) size++;
213 bitmap = malloc(size);
215 printf("ERROR: could not allocate space for bitmap\n");
219 memset(bitmap, 0, size);
221 for (i = 0 ; j < bitmap_entries - 1; i++) {
222 struct dirent * tmp_dir = namelist[i];
224 char status_str[BUF_SIZE];
225 char fname[BUF_SIZE];
227 memset(status_str, 0, BUF_SIZE);
228 memset(fname, 0, BUF_SIZE);
230 snprintf(fname, BUF_SIZE, "%s%s/removable", SYS_PATH, tmp_dir->d_name);
232 j = atoi(tmp_dir->d_name + 6);
238 printf("Skipping %s due to minimum start constraint\n",fname);
242 if (limit32 && i>limit_block) {
243 printf("Skipping %s due to 32 bit constraint\n",fname);
248 printf("Checking %s...", fname);
250 block_fd = open(fname, O_RDONLY);
252 if (block_fd == -1) {
253 printf("Hotpluggable memory not supported...\n");
257 if (read(block_fd, status_str, BUF_SIZE) <= 0) {
258 perror("Could not read block status");
264 if (atoi(status_str) == 1) {
265 printf("Removable\n");
266 bitmap[major] |= (0x1 << minor);
268 printf("Not removable\n");
277 /* Scan bitmap for enough consecutive space */
279 // num_blocks: The number of blocks we need to find
280 // bitmap: bitmap of blocks (1 == allocatable)
281 // bitmap_entries: number of blocks in the system/number of bits in bitmap
282 // reg_start: The block index where our allocation will start
287 for (i = 0; i < bitmap_entries; i++) {
291 if (!(bitmap[i_major] & (0x1 << i_minor))) {
292 reg_start = i + 1; // skip the region start to next entry
299 if (run_len >= num_blocks) {
305 if (run_len < num_blocks) {
306 fprintf(stderr, "Could not find enough consecutive memory blocks... (found %d)\n", run_len);
312 /* Offline memory blocks starting at reg_start */
316 for (i = 0; i < num_blocks; i++) {
317 FILE * block_file = NULL;
320 memset(fname, 0, 256);
322 snprintf(fname, 256, "%smemory%d/state", SYS_PATH, i + reg_start);
324 block_file = fopen(fname, "r+");
326 if (block_file == NULL) {
327 perror("Could not open block file");
332 printf("Offlining block %d (%s)\n", i + reg_start, fname);
333 fprintf(block_file, "offline\n");
340 /* We asked to offline set of blocks, but Linux could have lied.
341 * To be safe, check whether blocks were offlined and start again if not
347 mem_ready = 1; // Hopefully we are ok...
350 for (i = 0; i < num_blocks; i++) {
352 char fname[BUF_SIZE];
353 char status_buf[BUF_SIZE];
356 memset(fname, 0, BUF_SIZE);
357 memset(status_buf, 0, BUF_SIZE);
359 snprintf(fname, BUF_SIZE, "%smemory%d/state", SYS_PATH, i + reg_start);
362 block_fd = open(fname, O_RDONLY);
364 if (block_fd == -1) {
365 perror("Could not open block file");
369 if (read(block_fd, status_buf, BUF_SIZE) <= 0) {
370 perror("Could not read block status");
374 printf("Checking offlined block %d (%s)...", i + reg_start, fname);
376 int ret = strncmp(status_buf, "offline", strlen("offline"));
380 int major = (i + reg_start) / 8;
381 int minor = (i + reg_start) % 8;
383 bitmap[major] &= ~(0x1 << minor); // mark the block as not removable in bitmap
385 mem_ready = 0; // Keep searching
387 printf("ERROR (%d)\n", ret);
389 for (j = 0; j < i; j++) {
390 FILE * block_file = NULL;
393 memset(fname, 0, 256);
395 snprintf(fname, 256, "%smemory%d/state", SYS_PATH, j + reg_start);
397 block_file = fopen(fname, "r+");
399 if (block_file == NULL) {
400 perror("Could not open block file");
404 fprintf(block_file, "online\n");
422 /* Memory is offlined. Calculate size and phys start addr to send to Palacios */
423 *num_bytes = (unsigned long long)(num_blocks) * (unsigned long long)(block_size_bytes);
424 *base_addr = (unsigned long long)(reg_start) * (unsigned long long)(block_size_bytes);