Commit ea88812f4f4fa19e08a665fb75a38ffa6d87715f
1 parent
58fe2f10
added OS dependent functions (temporary as most functions are generic in fact)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@624 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
485 additions
and
0 deletions
osdep.c
0 → 100644
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 <sys/mman.h> | ||
29 | +#include <sys/ipc.h> | ||
30 | +#include <errno.h> | ||
31 | +#include <unistd.h> | ||
32 | + | ||
33 | +#include "cpu.h" | ||
34 | + | ||
35 | +#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) | ||
36 | + | ||
37 | +/* When not using soft mmu, libc independant functions are needed for | ||
38 | + the CPU core because it needs to use alternates stacks and | ||
39 | + libc/thread incompatibles settings */ | ||
40 | + | ||
41 | +#include <linux/unistd.h> | ||
42 | + | ||
43 | +#define QEMU_SYSCALL0(name) \ | ||
44 | +{ \ | ||
45 | +long __res; \ | ||
46 | +__asm__ volatile ("int $0x80" \ | ||
47 | + : "=a" (__res) \ | ||
48 | + : "0" (__NR_##name)); \ | ||
49 | +return __res; \ | ||
50 | +} | ||
51 | + | ||
52 | +#define QEMU_SYSCALL1(name,arg1) \ | ||
53 | +{ \ | ||
54 | +long __res; \ | ||
55 | +__asm__ volatile ("int $0x80" \ | ||
56 | + : "=a" (__res) \ | ||
57 | + : "0" (__NR_##name),"b" ((long)(arg1))); \ | ||
58 | +return __res; \ | ||
59 | +} | ||
60 | + | ||
61 | +#define QEMU_SYSCALL2(name,arg1,arg2) \ | ||
62 | +{ \ | ||
63 | +long __res; \ | ||
64 | +__asm__ volatile ("int $0x80" \ | ||
65 | + : "=a" (__res) \ | ||
66 | + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \ | ||
67 | +return __res; \ | ||
68 | +} | ||
69 | + | ||
70 | +#define QEMU_SYSCALL3(name,arg1,arg2,arg3) \ | ||
71 | +{ \ | ||
72 | +long __res; \ | ||
73 | +__asm__ volatile ("int $0x80" \ | ||
74 | + : "=a" (__res) \ | ||
75 | + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ | ||
76 | + "d" ((long)(arg3))); \ | ||
77 | +return __res; \ | ||
78 | +} | ||
79 | + | ||
80 | +#define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \ | ||
81 | +{ \ | ||
82 | +long __res; \ | ||
83 | +__asm__ volatile ("int $0x80" \ | ||
84 | + : "=a" (__res) \ | ||
85 | + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ | ||
86 | + "d" ((long)(arg3)),"S" ((long)(arg4))); \ | ||
87 | +return __res; \ | ||
88 | +} | ||
89 | + | ||
90 | +#define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \ | ||
91 | +{ \ | ||
92 | +long __res; \ | ||
93 | +__asm__ volatile ("int $0x80" \ | ||
94 | + : "=a" (__res) \ | ||
95 | + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ | ||
96 | + "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ | ||
97 | +return __res; \ | ||
98 | +} | ||
99 | + | ||
100 | +#define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \ | ||
101 | +{ \ | ||
102 | +long __res; \ | ||
103 | +__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \ | ||
104 | + : "=a" (__res) \ | ||
105 | + : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ | ||
106 | + "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \ | ||
107 | + "0" ((long)(arg6))); \ | ||
108 | +return __res; \ | ||
109 | +} | ||
110 | + | ||
111 | +int qemu_write(int fd, const void *buf, size_t n) | ||
112 | +{ | ||
113 | + QEMU_SYSCALL3(write, fd, buf, n); | ||
114 | +} | ||
115 | + | ||
116 | + | ||
117 | + | ||
118 | +/****************************************************************/ | ||
119 | +/* shmat replacement */ | ||
120 | + | ||
121 | +int qemu_ipc(int call, unsigned long first, | ||
122 | + unsigned long second, unsigned long third, | ||
123 | + void *ptr, unsigned long fifth) | ||
124 | +{ | ||
125 | + QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth); | ||
126 | +} | ||
127 | + | ||
128 | +#define SHMAT 21 | ||
129 | + | ||
130 | +/* we must define shmat so that a specific address will be used when | ||
131 | + mapping the X11 ximage */ | ||
132 | +void *shmat(int shmid, const void *shmaddr, int shmflg) | ||
133 | +{ | ||
134 | + void *ptr; | ||
135 | + int ret; | ||
136 | + /* we give an address in the right memory area */ | ||
137 | + if (!shmaddr) | ||
138 | + shmaddr = get_mmap_addr(8192 * 1024); | ||
139 | + ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0); | ||
140 | + if (ret < 0) | ||
141 | + return NULL; | ||
142 | + return ptr; | ||
143 | +} | ||
144 | + | ||
145 | +/****************************************************************/ | ||
146 | +/* memory allocation */ | ||
147 | + | ||
148 | +//#define DEBUG_MALLOC | ||
149 | + | ||
150 | +#define MALLOC_BASE 0xab000000 | ||
151 | +#define PHYS_RAM_BASE 0xac000000 | ||
152 | + | ||
153 | +#define MALLOC_ALIGN 16 | ||
154 | +#define BLOCK_HEADER_SIZE 16 | ||
155 | + | ||
156 | +typedef struct MemoryBlock { | ||
157 | + struct MemoryBlock *next; | ||
158 | + unsigned long size; /* size of block, including header */ | ||
159 | +} MemoryBlock; | ||
160 | + | ||
161 | +static MemoryBlock *first_free_block; | ||
162 | +static unsigned long malloc_addr = MALLOC_BASE; | ||
163 | + | ||
164 | +static void *malloc_get_space(size_t size) | ||
165 | +{ | ||
166 | + void *ptr; | ||
167 | + size = TARGET_PAGE_ALIGN(size); | ||
168 | + ptr = mmap((void *)malloc_addr, size, | ||
169 | + PROT_WRITE | PROT_READ, | ||
170 | + MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0); | ||
171 | + if (ptr == MAP_FAILED) | ||
172 | + return NULL; | ||
173 | + malloc_addr += size; | ||
174 | + return ptr; | ||
175 | +} | ||
176 | + | ||
177 | +void *qemu_malloc(size_t size) | ||
178 | +{ | ||
179 | + MemoryBlock *mb, *mb1, **pmb; | ||
180 | + void *ptr; | ||
181 | + size_t size1, area_size; | ||
182 | + | ||
183 | + if (size == 0) | ||
184 | + return NULL; | ||
185 | + | ||
186 | + size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1); | ||
187 | + pmb = &first_free_block; | ||
188 | + for(;;) { | ||
189 | + mb = *pmb; | ||
190 | + if (mb == NULL) | ||
191 | + break; | ||
192 | + if (size <= mb->size) | ||
193 | + goto found; | ||
194 | + pmb = &mb->next; | ||
195 | + } | ||
196 | + /* no big enough blocks found: get new space */ | ||
197 | + area_size = TARGET_PAGE_ALIGN(size); | ||
198 | + mb = malloc_get_space(area_size); | ||
199 | + if (!mb) | ||
200 | + return NULL; | ||
201 | + size1 = area_size - size; | ||
202 | + if (size1 > 0) { | ||
203 | + /* create a new free block */ | ||
204 | + mb1 = (MemoryBlock *)((uint8_t *)mb + size); | ||
205 | + mb1->next = NULL; | ||
206 | + mb1->size = size1; | ||
207 | + *pmb = mb1; | ||
208 | + } | ||
209 | + goto the_end; | ||
210 | + found: | ||
211 | + /* a free block was found: use it */ | ||
212 | + size1 = mb->size - size; | ||
213 | + if (size1 > 0) { | ||
214 | + /* create a new free block */ | ||
215 | + mb1 = (MemoryBlock *)((uint8_t *)mb + size); | ||
216 | + mb1->next = mb->next; | ||
217 | + mb1->size = size1; | ||
218 | + *pmb = mb1; | ||
219 | + } else { | ||
220 | + /* suppress the first block */ | ||
221 | + *pmb = mb->next; | ||
222 | + } | ||
223 | + the_end: | ||
224 | + mb->size = size; | ||
225 | + mb->next = NULL; | ||
226 | + ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE); | ||
227 | +#ifdef DEBUG_MALLOC | ||
228 | + qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr); | ||
229 | +#endif | ||
230 | + return ptr; | ||
231 | +} | ||
232 | + | ||
233 | +void qemu_free(void *ptr) | ||
234 | +{ | ||
235 | + MemoryBlock *mb; | ||
236 | + | ||
237 | + mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE); | ||
238 | + mb->next = first_free_block; | ||
239 | + first_free_block = mb; | ||
240 | +} | ||
241 | + | ||
242 | +/****************************************************************/ | ||
243 | +/* virtual memory allocation */ | ||
244 | + | ||
245 | +unsigned long mmap_addr = PHYS_RAM_BASE; | ||
246 | + | ||
247 | +void *get_mmap_addr(unsigned long size) | ||
248 | +{ | ||
249 | + unsigned long addr; | ||
250 | + addr = mmap_addr; | ||
251 | + mmap_addr += ((size + 4095) & ~4095) + 4096; | ||
252 | + return (void *)addr; | ||
253 | +} | ||
254 | + | ||
255 | +#else | ||
256 | + | ||
257 | +int qemu_write(int fd, const void *buf, size_t n) | ||
258 | +{ | ||
259 | + int ret; | ||
260 | + ret = write(fd, buf, n); | ||
261 | + if (ret < 0) | ||
262 | + return -errno; | ||
263 | + else | ||
264 | + return ret; | ||
265 | +} | ||
266 | + | ||
267 | +void *get_mmap_addr(unsigned long size) | ||
268 | +{ | ||
269 | + return NULL; | ||
270 | +} | ||
271 | + | ||
272 | +void qemu_free(void *ptr) | ||
273 | +{ | ||
274 | + free(ptr); | ||
275 | +} | ||
276 | + | ||
277 | +void *qemu_malloc(size_t size) | ||
278 | +{ | ||
279 | + return malloc(size); | ||
280 | +} | ||
281 | + | ||
282 | +#endif | ||
283 | + | ||
284 | +/****************************************************************/ | ||
285 | +/* printf support */ | ||
286 | + | ||
287 | +static inline int qemu_isdigit(int c) | ||
288 | +{ | ||
289 | + return c >= '0' && c <= '9'; | ||
290 | +} | ||
291 | + | ||
292 | +#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) | ||
293 | + | ||
294 | +/* from BSD ppp sources */ | ||
295 | +int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args) | ||
296 | +{ | ||
297 | + int c, i, n; | ||
298 | + int width, prec, fillch; | ||
299 | + int base, len, neg; | ||
300 | + unsigned long val = 0; | ||
301 | + const char *f; | ||
302 | + char *str, *buf0; | ||
303 | + char num[32]; | ||
304 | + static const char hexchars[] = "0123456789abcdef"; | ||
305 | + | ||
306 | + buf0 = buf; | ||
307 | + --buflen; | ||
308 | + while (buflen > 0) { | ||
309 | + for (f = fmt; *f != '%' && *f != 0; ++f) | ||
310 | + ; | ||
311 | + if (f > fmt) { | ||
312 | + len = f - fmt; | ||
313 | + if (len > buflen) | ||
314 | + len = buflen; | ||
315 | + memcpy(buf, fmt, len); | ||
316 | + buf += len; | ||
317 | + buflen -= len; | ||
318 | + fmt = f; | ||
319 | + } | ||
320 | + if (*fmt == 0) | ||
321 | + break; | ||
322 | + c = *++fmt; | ||
323 | + width = prec = 0; | ||
324 | + fillch = ' '; | ||
325 | + if (c == '0') { | ||
326 | + fillch = '0'; | ||
327 | + c = *++fmt; | ||
328 | + } | ||
329 | + if (c == '*') { | ||
330 | + width = va_arg(args, int); | ||
331 | + c = *++fmt; | ||
332 | + } else { | ||
333 | + while (qemu_isdigit(c)) { | ||
334 | + width = width * 10 + c - '0'; | ||
335 | + c = *++fmt; | ||
336 | + } | ||
337 | + } | ||
338 | + if (c == '.') { | ||
339 | + c = *++fmt; | ||
340 | + if (c == '*') { | ||
341 | + prec = va_arg(args, int); | ||
342 | + c = *++fmt; | ||
343 | + } else { | ||
344 | + while (qemu_isdigit(c)) { | ||
345 | + prec = prec * 10 + c - '0'; | ||
346 | + c = *++fmt; | ||
347 | + } | ||
348 | + } | ||
349 | + } | ||
350 | + /* modifiers */ | ||
351 | + switch(c) { | ||
352 | + case 'l': | ||
353 | + c = *++fmt; | ||
354 | + break; | ||
355 | + default: | ||
356 | + break; | ||
357 | + } | ||
358 | + str = 0; | ||
359 | + base = 0; | ||
360 | + neg = 0; | ||
361 | + ++fmt; | ||
362 | + switch (c) { | ||
363 | + case 'd': | ||
364 | + i = va_arg(args, int); | ||
365 | + if (i < 0) { | ||
366 | + neg = 1; | ||
367 | + val = -i; | ||
368 | + } else | ||
369 | + val = i; | ||
370 | + base = 10; | ||
371 | + break; | ||
372 | + case 'o': | ||
373 | + val = va_arg(args, unsigned int); | ||
374 | + base = 8; | ||
375 | + break; | ||
376 | + case 'x': | ||
377 | + case 'X': | ||
378 | + val = va_arg(args, unsigned int); | ||
379 | + base = 16; | ||
380 | + break; | ||
381 | + case 'p': | ||
382 | + val = (unsigned long) va_arg(args, void *); | ||
383 | + base = 16; | ||
384 | + neg = 2; | ||
385 | + break; | ||
386 | + case 's': | ||
387 | + str = va_arg(args, char *); | ||
388 | + break; | ||
389 | + case 'c': | ||
390 | + num[0] = va_arg(args, int); | ||
391 | + num[1] = 0; | ||
392 | + str = num; | ||
393 | + break; | ||
394 | + default: | ||
395 | + *buf++ = '%'; | ||
396 | + if (c != '%') | ||
397 | + --fmt; /* so %z outputs %z etc. */ | ||
398 | + --buflen; | ||
399 | + continue; | ||
400 | + } | ||
401 | + if (base != 0) { | ||
402 | + str = num + sizeof(num); | ||
403 | + *--str = 0; | ||
404 | + while (str > num + neg) { | ||
405 | + *--str = hexchars[val % base]; | ||
406 | + val = val / base; | ||
407 | + if (--prec <= 0 && val == 0) | ||
408 | + break; | ||
409 | + } | ||
410 | + switch (neg) { | ||
411 | + case 1: | ||
412 | + *--str = '-'; | ||
413 | + break; | ||
414 | + case 2: | ||
415 | + *--str = 'x'; | ||
416 | + *--str = '0'; | ||
417 | + break; | ||
418 | + } | ||
419 | + len = num + sizeof(num) - 1 - str; | ||
420 | + } else { | ||
421 | + len = strlen(str); | ||
422 | + if (prec > 0 && len > prec) | ||
423 | + len = prec; | ||
424 | + } | ||
425 | + if (width > 0) { | ||
426 | + if (width > buflen) | ||
427 | + width = buflen; | ||
428 | + if ((n = width - len) > 0) { | ||
429 | + buflen -= n; | ||
430 | + for (; n > 0; --n) | ||
431 | + *buf++ = fillch; | ||
432 | + } | ||
433 | + } | ||
434 | + if (len > buflen) | ||
435 | + len = buflen; | ||
436 | + memcpy(buf, str, len); | ||
437 | + buf += len; | ||
438 | + buflen -= len; | ||
439 | + } | ||
440 | + *buf = 0; | ||
441 | + return buf - buf0; | ||
442 | +} | ||
443 | + | ||
444 | +void qemu_vprintf(const char *fmt, va_list ap) | ||
445 | +{ | ||
446 | + char buf[1024]; | ||
447 | + int len; | ||
448 | + | ||
449 | + len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap); | ||
450 | + qemu_write(1, buf, len); | ||
451 | +} | ||
452 | + | ||
453 | +void qemu_printf(const char *fmt, ...) | ||
454 | +{ | ||
455 | + va_list ap; | ||
456 | + va_start(ap, fmt); | ||
457 | + qemu_vprintf(fmt, ap); | ||
458 | + va_end(ap); | ||
459 | +} | ||
460 | + |
osdep.h
0 → 100644
1 | +#ifndef QEMU_OSDEP_H | ||
2 | +#define QEMU_OSDEP_H | ||
3 | + | ||
4 | +#include <stdarg.h> | ||
5 | + | ||
6 | +int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args); | ||
7 | +void qemu_vprintf(const char *fmt, va_list ap); | ||
8 | +void qemu_printf(const char *fmt, ...); | ||
9 | + | ||
10 | +void *qemu_malloc(size_t size); | ||
11 | +void qemu_free(void *ptr); | ||
12 | + | ||
13 | +void *get_mmap_addr(unsigned long size); | ||
14 | + | ||
15 | +/* specific kludges for OS compatibility (should be moved elsewhere) */ | ||
16 | +#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) | ||
17 | + | ||
18 | +/* disabled pthread version of longjmp which prevent us from using an | ||
19 | + alternative signal stack */ | ||
20 | +extern void __longjmp(jmp_buf env, int val); | ||
21 | +#define longjmp __longjmp | ||
22 | + | ||
23 | +#endif | ||
24 | + | ||
25 | +#endif |