removed unused code
[qemu] / osdep.c
1 /*
2  * QEMU low level functions
3  * 
4  * Copyright (c) 2003 Fabrice Bellard
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <unistd.h>
30
31 #include "cpu.h"
32 #if defined(USE_KQEMU)
33 #include "vl.h"
34 #endif
35
36 #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
37
38 #include <sys/mman.h>
39 #include <sys/ipc.h>
40
41 /* When not using soft mmu, libc independant functions are needed for
42    the CPU core because it needs to use alternates stacks and
43    libc/thread incompatibles settings */
44
45 #include <linux/unistd.h>
46
47 #define QEMU_SYSCALL0(name) \
48 { \
49 long __res; \
50 __asm__ volatile ("int $0x80" \
51         : "=a" (__res) \
52         : "0" (__NR_##name)); \
53 return __res; \
54 }
55
56 #define QEMU_SYSCALL1(name,arg1) \
57 { \
58 long __res; \
59 __asm__ volatile ("int $0x80" \
60         : "=a" (__res) \
61         : "0" (__NR_##name),"b" ((long)(arg1))); \
62 return __res; \
63 }
64
65 #define QEMU_SYSCALL2(name,arg1,arg2) \
66 { \
67 long __res; \
68 __asm__ volatile ("int $0x80" \
69         : "=a" (__res) \
70         : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
71 return __res; \
72 }
73
74 #define QEMU_SYSCALL3(name,arg1,arg2,arg3) \
75 { \
76 long __res; \
77 __asm__ volatile ("int $0x80" \
78         : "=a" (__res) \
79         : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
80                   "d" ((long)(arg3))); \
81 return __res; \
82 }
83
84 #define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \
85 { \
86 long __res; \
87 __asm__ volatile ("int $0x80" \
88         : "=a" (__res) \
89         : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
90           "d" ((long)(arg3)),"S" ((long)(arg4))); \
91 return __res; \
92
93
94 #define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \
95 { \
96 long __res; \
97 __asm__ volatile ("int $0x80" \
98         : "=a" (__res) \
99         : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
100           "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
101 return __res; \
102 }
103
104 #define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
105 { \
106 long __res; \
107 __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
108         : "=a" (__res) \
109         : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
110           "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
111           "0" ((long)(arg6))); \
112 return __res; \
113 }
114
115 /****************************************************************/
116 /* shmat replacement */
117
118 int qemu_ipc(int call, unsigned long first, 
119             unsigned long second, unsigned long third, 
120             void *ptr, unsigned long fifth)
121 {
122     QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
123 }
124
125 #define SHMAT 21
126
127 /* we must define shmat so that a specific address will be used when
128    mapping the X11 ximage */
129 void *shmat(int shmid, const void *shmaddr, int shmflg)
130 {
131     void *ptr;
132     int ret;
133     /* we give an address in the right memory area */
134     if (!shmaddr)
135         shmaddr = get_mmap_addr(8192 * 1024);
136     ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0);
137     if (ret < 0)
138         return NULL;
139     return ptr;
140 }
141
142 /****************************************************************/
143 /* sigaction bypassing the threads */
144
145 static int kernel_sigaction(int signum, const struct qemu_sigaction *act, 
146                             struct qemu_sigaction *oldact, 
147                             int sigsetsize)
148 {
149     QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize);
150 }
151
152 int qemu_sigaction(int signum, const struct qemu_sigaction *act, 
153                    struct qemu_sigaction *oldact)
154 {
155     return kernel_sigaction(signum, act, oldact, 8);
156 }
157
158 /****************************************************************/
159 /* memory allocation */
160
161 //#define DEBUG_MALLOC
162
163 #define MALLOC_BASE       0xab000000
164 #define PHYS_RAM_BASE     0xac000000
165
166 #define MALLOC_ALIGN      16
167 #define BLOCK_HEADER_SIZE 16
168
169 typedef struct MemoryBlock {
170     struct MemoryBlock *next;
171     unsigned long size; /* size of block, including header */
172 } MemoryBlock;
173
174 static MemoryBlock *first_free_block;
175 static unsigned long malloc_addr = MALLOC_BASE;
176
177 static void *malloc_get_space(size_t size)
178 {
179     void *ptr;
180     size = TARGET_PAGE_ALIGN(size);
181     ptr = mmap((void *)malloc_addr, size, 
182                PROT_WRITE | PROT_READ, 
183                MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
184     if (ptr == MAP_FAILED)
185         return NULL;
186     malloc_addr += size;
187     return ptr;
188 }
189
190 void *qemu_malloc(size_t size)
191 {
192     MemoryBlock *mb, *mb1, **pmb;
193     void *ptr;
194     size_t size1, area_size;
195     
196     if (size == 0)
197         return NULL;
198
199     size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1);
200     pmb = &first_free_block;
201     for(;;) {
202         mb = *pmb;
203         if (mb == NULL)
204             break;
205         if (size <= mb->size)
206             goto found;
207         pmb = &mb->next;
208     }
209     /* no big enough blocks found: get new space */
210     area_size = TARGET_PAGE_ALIGN(size);
211     mb = malloc_get_space(area_size);
212     if (!mb)
213         return NULL;
214     size1 = area_size - size;
215     if (size1 > 0) {
216         /* create a new free block */
217         mb1 = (MemoryBlock *)((uint8_t *)mb + size);
218         mb1->next = NULL;
219         mb1->size = size1;
220         *pmb = mb1;
221     }
222     goto the_end;
223  found:
224     /* a free block was found: use it */
225     size1 = mb->size - size;
226     if (size1 > 0) {
227         /* create a new free block */
228         mb1 = (MemoryBlock *)((uint8_t *)mb + size);
229         mb1->next = mb->next;
230         mb1->size = size1;
231         *pmb = mb1;
232     } else {
233         /* suppress the first block */
234         *pmb = mb->next;
235     }
236  the_end:
237     mb->size = size;
238     mb->next = NULL;
239     ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE);
240 #ifdef DEBUG_MALLOC
241     qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr);
242 #endif
243     return ptr;
244 }
245
246 void qemu_free(void *ptr)
247 {
248     MemoryBlock *mb;
249
250     if (!ptr)
251         return;
252     mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
253     mb->next = first_free_block;
254     first_free_block = mb;
255 }
256
257 /****************************************************************/
258 /* virtual memory allocation */
259
260 unsigned long mmap_addr = PHYS_RAM_BASE;
261
262 void *get_mmap_addr(unsigned long size)
263 {
264     unsigned long addr;
265     addr = mmap_addr;
266     mmap_addr += ((size + 4095) & ~4095) + 4096;
267     return (void *)addr;
268 }
269
270 #else
271
272 #ifdef _WIN32
273 #include <windows.h>
274 #elif defined(_BSD)
275 #include <stdlib.h>
276 #else
277 #include <malloc.h>
278 #endif
279
280 void *get_mmap_addr(unsigned long size)
281 {
282     return NULL;
283 }
284
285 void qemu_free(void *ptr)
286 {
287     free(ptr);
288 }
289
290 void *qemu_malloc(size_t size)
291 {
292     return malloc(size);
293 }
294
295 #if defined(_WIN32)
296
297 void *qemu_vmalloc(size_t size)
298 {
299     /* FIXME: this is not exactly optimal solution since VirtualAlloc
300        has 64Kb granularity, but at least it guarantees us that the
301        memory is page aligned. */
302     return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
303 }
304
305 void qemu_vfree(void *ptr)
306 {
307     VirtualFree(ptr, 0, MEM_RELEASE);
308 }
309
310 #else
311
312 #if defined(USE_KQEMU)
313
314 #include <sys/vfs.h>
315 #include <sys/mman.h>
316 #include <fcntl.h>
317
318 void *kqemu_vmalloc(size_t size)
319 {
320     static int phys_ram_fd = -1;
321     static int phys_ram_size = 0;
322     const char *tmpdir;
323     char phys_ram_file[1024];
324     void *ptr;
325     struct statfs stfs;
326
327     if (phys_ram_fd < 0) {
328         tmpdir = getenv("QEMU_TMPDIR");
329         if (!tmpdir)
330             tmpdir = "/dev/shm";
331         if (statfs(tmpdir, &stfs) == 0) {
332             int64_t free_space;
333             int ram_mb;
334
335             extern int ram_size;
336             free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
337             if ((ram_size + 8192 * 1024) >= free_space) {
338                 ram_mb = (ram_size / (1024 * 1024));
339                 fprintf(stderr, 
340                         "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
341                         tmpdir, ram_mb);
342                 if (strcmp(tmpdir, "/dev/shm") == 0) {
343                     fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n"
344                             "umount /dev/shm\n"
345                             "mount -t tmpfs -o size=%dm none /dev/shm\n",
346                             ram_mb + 16);
347                 } else {
348                     fprintf(stderr, 
349                             "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
350                             "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
351                             "temporary RAM file will be opened.\n");
352                 }
353                 fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
354                 exit(1);
355             }
356         }
357         snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
358                  tmpdir);
359         if (mkstemp(phys_ram_file) < 0) {
360             fprintf(stderr, 
361                     "warning: could not create temporary file in '%s'.\n"
362                     "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
363                     "Using '/tmp' as fallback.\n",
364                     tmpdir);
365             snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
366                      "/tmp");
367             if (mkstemp(phys_ram_file) < 0) {
368                 fprintf(stderr, "Could not create temporary memory file '%s'\n", 
369                         phys_ram_file);
370                 exit(1);
371             }
372         }
373         phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
374         if (phys_ram_fd < 0) {
375             fprintf(stderr, "Could not open temporary memory file '%s'\n", 
376                     phys_ram_file);
377             exit(1);
378         }
379         unlink(phys_ram_file);
380     }
381     size = (size + 4095) & ~4095;
382     ftruncate(phys_ram_fd, phys_ram_size + size);
383     ptr = mmap(NULL, 
384                size, 
385                PROT_WRITE | PROT_READ, MAP_SHARED, 
386                phys_ram_fd, phys_ram_size);
387     if (ptr == MAP_FAILED) {
388         fprintf(stderr, "Could not map physical memory\n");
389         exit(1);
390     }
391     phys_ram_size += size;
392     return ptr;
393 }
394
395 void kqemu_vfree(void *ptr)
396 {
397     /* may be useful some day, but currently we do not need to free */
398 }
399
400 #endif
401
402 /* alloc shared memory pages */
403 void *qemu_vmalloc(size_t size)
404 {
405 #if defined(USE_KQEMU)
406     if (kqemu_allowed)
407         return kqemu_vmalloc(size);
408 #endif
409 #ifdef _BSD
410     return valloc(size);
411 #else
412     return memalign(4096, size);
413 #endif
414 }
415
416 void qemu_vfree(void *ptr)
417 {
418 #if defined(USE_KQEMU)
419     if (kqemu_allowed)
420         kqemu_vfree(ptr);
421 #endif
422     free(ptr);
423 }
424
425 #endif
426
427 #endif
428
429 void *qemu_mallocz(size_t size)
430 {
431     void *ptr;
432     ptr = qemu_malloc(size);
433     if (!ptr)
434         return NULL;
435     memset(ptr, 0, size);
436     return ptr;
437 }
438
439 char *qemu_strdup(const char *str)
440 {
441     char *ptr;
442     ptr = qemu_malloc(strlen(str) + 1);
443     if (!ptr)
444         return NULL;
445     strcpy(ptr, str);
446     return ptr;
447 }