10 #include <sys/ioctl.h>
12 #include <sys/types.h>
19 #define SYS_PATH "/sys/devices/system/memory/"
23 int dir_filter(const struct dirent * dir) {
24 if (strncmp("memory", dir->d_name, 6) == 0) {
33 int dir_cmp(const struct dirent **dir1, const struct dirent ** dir2) {
34 int num1 = atoi((*dir1)->d_name + 6);
35 int num2 = atoi((*dir2)->d_name + 6);
42 int main(int argc, char * argv[]) {
43 unsigned long long mem_size_bytes = 0;
44 unsigned long long mem_min_start = 0;
45 unsigned int block_size_bytes = 0;
46 int bitmap_entries = 0;
47 unsigned char * bitmap = NULL;
52 if (argc != 2 && argc != 3) {
53 printf("usage: v3_mem <memory size (MB)> [min_start (MB)]\n\n"
54 "Offline memory for use in Palacios.\n"
55 "min_start is the minimum allowable starting address.\n"
56 "this is zero by default\n\n");
61 mem_size_bytes = atoll(argv[1]) * (1024 * 1024);
64 mem_min_start = atoll(argv[1]) * (1024 * 1024);
67 printf("Trying to find %dMB (%d bytes) of memory above %llu\n", atoll(argv[1]), mem_size_bytes, mem_min_start);
69 /* Figure out the block size */
72 char tmp_buf[BUF_SIZE];
74 tmp_fd = open(SYS_PATH "block_size_bytes", O_RDONLY);
77 perror("Could not open block size file: " SYS_PATH "block_size_bytes");
81 if (read(tmp_fd, tmp_buf, BUF_SIZE) <= 0) {
82 perror("Could not read block size file: " SYS_PATH "block_size_bytes");
88 block_size_bytes = strtoll(tmp_buf, NULL, 16);
90 printf("Memory block size is %dMB (%d bytes)\n", block_size_bytes / (1024 * 1024), block_size_bytes);
95 num_blocks = mem_size_bytes / block_size_bytes;
96 if (mem_size_bytes % block_size_bytes) num_blocks++;
98 mem_min_start = block_size_bytes *
99 ((mem_min_start / block_size_bytes) + (!!(mem_min_start % block_size_bytes)));
101 printf("Looking for %d blocks of memory starting at %p (block %llu)\n", num_blocks, (void*)mem_min_start, mem_min_start/block_size_bytes);
104 // We now need to find <num_blocks> consecutive offlinable memory blocks
106 /* Scan the memory directories */
108 struct dirent ** namelist = NULL;
113 int first_block = mem_min_start/block_size_bytes;
115 last_block = scandir(SYS_PATH, &namelist, dir_filter, dir_cmp);
116 bitmap_entries = atoi(namelist[last_block - 1]->d_name + 6) + 1;
118 size = bitmap_entries / 8;
119 if (bitmap_entries % 8) size++;
121 bitmap = malloc(size);
123 printf("ERROR: could not allocate space for bitmap\n");
127 memset(bitmap, 0, size);
129 for (i = 0 ; j < bitmap_entries - 1; i++) {
130 struct dirent * tmp_dir = namelist[i];
132 char status_str[BUF_SIZE];
133 char fname[BUF_SIZE];
135 memset(status_str, 0, BUF_SIZE);
136 memset(fname, 0, BUF_SIZE);
138 snprintf(fname, BUF_SIZE, "%s%s/removable", SYS_PATH, tmp_dir->d_name);
140 j = atoi(tmp_dir->d_name + 6);
146 printf("Skipping %s due to minimum start constraint\n",fname);
150 printf("Checking %s...", fname);
152 block_fd = open(fname, O_RDONLY);
154 if (block_fd == -1) {
155 printf("Hotpluggable memory not supported...\n");
159 if (read(block_fd, status_str, BUF_SIZE) <= 0) {
160 perror("Could not read block status");
166 if (atoi(status_str) == 1) {
167 printf("Removable\n");
168 bitmap[major] |= (0x1 << minor);
170 printf("Not removable\n");
179 /* Scan bitmap for enough consecutive space */
181 // num_blocks: The number of blocks we need to find
182 // bitmap: bitmap of blocks (1 == allocatable)
183 // bitmap_entries: number of blocks in the system/number of bits in bitmap
184 // reg_start: The block index where our allocation will start
189 for (i = 0; i < bitmap_entries; i++) {
193 if (!(bitmap[i_major] & (0x1 << i_minor))) {
194 reg_start = i + 1; // skip the region start to next entry
201 if (run_len >= num_blocks) {
207 if (run_len < num_blocks) {
208 fprintf(stderr, "Could not find enough consecutive memory blocks... (found %d)\n", run_len);
214 /* Offline memory blocks starting at reg_start */
218 for (i = 0; i < num_blocks; i++) {
219 FILE * block_file = NULL;
222 memset(fname, 0, 256);
224 snprintf(fname, 256, "%smemory%d/state", SYS_PATH, i + reg_start);
226 block_file = fopen(fname, "r+");
228 if (block_file == NULL) {
229 perror("Could not open block file");
234 printf("Offlining block %d (%s)\n", i + reg_start, fname);
235 fprintf(block_file, "offline\n");
242 /* We asked to offline set of blocks, but Linux could have lied.
243 * To be safe, check whether blocks were offlined and start again if not
249 mem_ready = 1; // Hopefully we are ok...
252 for (i = 0; i < num_blocks; i++) {
254 char fname[BUF_SIZE];
255 char status_buf[BUF_SIZE];
258 memset(fname, 0, BUF_SIZE);
259 memset(status_buf, 0, BUF_SIZE);
261 snprintf(fname, BUF_SIZE, "%smemory%d/state", SYS_PATH, i + reg_start);
264 block_fd = open(fname, O_RDONLY);
266 if (block_fd == -1) {
267 perror("Could not open block file");
271 if (read(block_fd, status_buf, BUF_SIZE) <= 0) {
272 perror("Could not read block status");
276 printf("Checking offlined block %d (%s)...", i + reg_start, fname);
278 int ret = strncmp(status_buf, "offline", strlen("offline"));
282 int major = (i + reg_start) / 8;
283 int minor = (i + reg_start) % 8;
285 bitmap[major] &= ~(0x1 << minor); // mark the block as not removable in bitmap
287 mem_ready = 0; // Keep searching
289 printf("ERROR (%d)\n", ret);
291 for (j = 0; j < i; j++) {
292 FILE * block_file = NULL;
295 memset(fname, 0, 256);
297 snprintf(fname, 256, "%smemory%d/state", SYS_PATH, j + reg_start);
299 block_file = fopen(fname, "r+");
301 if (block_file == NULL) {
302 perror("Could not open block file");
306 fprintf(block_file, "online\n");
324 /* Memory is offlined. Calculate size and phys start addr to send to Palacios */
328 struct v3_mem_region mem;
329 unsigned long long num_bytes = (unsigned long long)(num_blocks) * (unsigned long long)(block_size_bytes);
330 unsigned long long base_addr = (unsigned long long)(reg_start) * (unsigned long long)(block_size_bytes);
332 printf("Giving Palacios %lluMB of memory at (%p) \n",
333 num_bytes / (1024 * 1024), base_addr);
335 mem.base_addr = base_addr;
336 mem.num_pages = num_bytes / 4096;
338 v3_fd = open(v3_dev, O_RDONLY);
341 printf("Error opening V3Vee control device\n");
345 ioctl(v3_fd, V3_ADD_MEMORY, &mem);
347 /* Close the file descriptor. */