社内勉強会のネタのフィードバックで…。

6月の社内勉強会の仮想化ネタに、QEMU & KQEMUの話をして、参加者が早速試してくれた。で、実メモリ4GBで、利用可能なメモリが2.7GBほどあったのに、メモリを2GB割り当てたら起動できなかったと聞き [1] 、ハードコーディングされているんじゃないかと、QEMUのソースコード読んでみたら案の定だった。

vl.c

101 #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024)

これじゃ、-m 2048とやったらダメだなぁ。でもなぜ2GB(2047MB)までにしているのかまでは分からず。どうしてなのだろう…。

以下は、qemu-0.9.0のコードよりメモリ割り当て関連のコードを抜粋。特定機能だけに注目して読めば読み易いなぁ。

vl.h

 167 /* XXX: make it dynamic */
 168 #if defined (TARGET_PPC) || defined (TARGET_SPARC64)
 169 #define BIOS_SIZE ((512 + 32) * 1024)
 170 #elif defined(TARGET_MIPS)
 171 #define BIOS_SIZE (4 * 1024 * 1024)
 172 #else
 173 #define BIOS_SIZE ((256 + 64) * 1024)
 174 #endif
~~~
 863 /* vga.c */
 864
 865 #define VGA_RAM_SIZE (8192 * 1024)

vl.c

 101 #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024)
 102
 103 #ifdef TARGET_PPC
 104 #define DEFAULT_RAM_SIZE 144
 105 #else
 106 #define DEFAULT_RAM_SIZE 128
 107 #endif
~~~
6145
6146 enum {
~~~
6162     QEMU_OPTION_m,
~~~
6209 };
~~~
6217 const QEMUOption qemu_options[] = {
~~~
6234     { "m", HAS_ARG, QEMU_OPTION_m },
~~~
6295     { NULL },
6296 };
~~~
6499 int main(int argc, char **argv)
6500 {
~~~
6565     ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
6566     vga_ram_size = VGA_RAM_SIZE;
6567     bios_size = BIOS_SIZE;
~~~
6603     for(;;) {
6604         if (optind >= argc)
6605             break;
6606         r = argv[optind];
6607         if (r[0] != '-') {
6608             hd_filename[0] = argv[optind++];
6609         } else {
~~~
6638             switch(popt->index) {
~~~
6783             case QEMU_OPTION_m:
6784                 ram_size = atoi(optarg) * 1024 * 1024;
6785                 if (ram_size <= 0)
6786                     help();
6787                 if (ram_size > PHYS_RAM_MAX_SIZE) {
6788                     fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n",
6789                             PHYS_RAM_MAX_SIZE / (1024 * 1024));
6790                     exit(1);
6791                 }
6792                 break;
~~~
6961             }
6962         }
6963     }
~~~
7080     /* init the memory */
7081     phys_ram_size = ram_size + vga_ram_size + bios_size;
7082
7083     for (i = 0; i < nb_option_roms; i++) {
7084         int ret = get_image_size(option_rom[i]);
7085         if (ret == -1) {
7086             fprintf(stderr, "Could not load option rom '%s'\n", option_rom[i]);
7087             exit(1);
7088         }
7089         phys_ram_size += ret;
7090     }
7091
7092     phys_ram_base = qemu_vmalloc(phys_ram_size);
7093     if (!phys_ram_base) {
7094         fprintf(stderr, "Could not allocate physical memory\n");
7095         exit(1);
7096     }
~~~
7269 }

osdep.c

 63 #if defined(_WIN32)
 64
 65 void *qemu_vmalloc(size_t size)
 66 {
 67     /* FIXME: this is not exactly optimal solution since VirtualAlloc
 68        has 64Kb granularity, but at least it guarantees us that the
 69        memory is page aligned. */
 70     return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
 71 }
~~~
 86 void *kqemu_vmalloc(size_t size)
 87 {
 88     static int phys_ram_fd = -1;
 89     static int phys_ram_size = 0;
 90     const char *tmpdir;
 91     char phys_ram_file[1024];
 92     void *ptr;
 93 #ifdef HOST_SOLARIS
 94     struct statvfs stfs;
 95 #else
 96     struct statfs stfs;
 97 #endif
 98
 99     if (phys_ram_fd < 0) {
100         tmpdir = getenv("QEMU_TMPDIR");
101         if (!tmpdir)
102 #ifdef HOST_SOLARIS
103             tmpdir = "/tmp";
104         if (statvfs(tmpdir, &stfs) == 0) {
105 #else
106             tmpdir = "/dev/shm";
107         if (statfs(tmpdir, &stfs) == 0) {
108 #endif
109             int64_t free_space;
110             int ram_mb;
111
112             extern int ram_size;
113             free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
114             if ((ram_size + 8192 * 1024) >= free_space) {
115                 ram_mb = (ram_size / (1024 * 1024));
116                 fprintf(stderr,
117                         "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
118                         tmpdir, ram_mb);
119                 if (strcmp(tmpdir, "/dev/shm") == 0) {
120                     fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n"
121                             "umount /dev/shm\n"
122                             "mount -t tmpfs -o size=%dm none /dev/shm\n",
123                             ram_mb + 16);
124                 } else {
125                     fprintf(stderr,
126                             "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
127                             "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
128                             "temporary RAM file will be opened.\n");
129                 }
130                 fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
131                 exit(1);
132             }
133         }
134         snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
135                  tmpdir);
136         phys_ram_fd = mkstemp(phys_ram_file);
137         if (phys_ram_fd < 0) {
138             fprintf(stderr,
139                     "warning: could not create temporary file in '%s'.\n"
140                     "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
141                     "Using '/tmp' as fallback.\n",
142                     tmpdir);
143             snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
144                      "/tmp");
145             phys_ram_fd = mkstemp(phys_ram_file);
146             if (phys_ram_fd < 0) {
147                 fprintf(stderr, "Could not create temporary memory file '%s'\n",
148                         phys_ram_file);
149                 exit(1);
150             }
151         }
152         unlink(phys_ram_file);
153     }
154     size = (size + 4095) & ~4095;
155     ftruncate(phys_ram_fd, phys_ram_size + size);
156     ptr = mmap(NULL,
157                size,
158                PROT_WRITE | PROT_READ, MAP_SHARED,
159                phys_ram_fd, phys_ram_size);
160     if (ptr == MAP_FAILED) {
161         fprintf(stderr, "Could not map physical memory\n");
162         exit(1);
163     }
164     phys_ram_size += size;
165     return ptr;
166 }
~~~
175 /* alloc shared memory pages */
176 void *qemu_vmalloc(size_t size)
177 {
178 #if defined(USE_KQEMU)
179     if (kqemu_allowed)
180         return kqemu_vmalloc(size);
181 #endif
182 #ifdef _BSD
183     return valloc(size);
184 #else
185     return memalign(4096, size);
186 #endif
187 }
[1]4GBもメモリ積んでるPC無いからそんなん知らんかった。