ia64/xen-unstable

view tools/ioemu/osdep.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 8e5fc5fe636c
children f7b43e5c42b9
line source
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>
31 #include "cpu.h"
33 #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
35 #include <sys/mman.h>
36 #include <sys/ipc.h>
38 /* When not using soft mmu, libc independant functions are needed for
39 the CPU core because it needs to use alternates stacks and
40 libc/thread incompatibles settings */
42 #include <linux/unistd.h>
44 #define QEMU_SYSCALL0(name) \
45 { \
46 long __res; \
47 __asm__ volatile ("int $0x80" \
48 : "=a" (__res) \
49 : "0" (__NR_##name)); \
50 return __res; \
51 }
53 #define QEMU_SYSCALL1(name,arg1) \
54 { \
55 long __res; \
56 __asm__ volatile ("int $0x80" \
57 : "=a" (__res) \
58 : "0" (__NR_##name),"b" ((long)(arg1))); \
59 return __res; \
60 }
62 #define QEMU_SYSCALL2(name,arg1,arg2) \
63 { \
64 long __res; \
65 __asm__ volatile ("int $0x80" \
66 : "=a" (__res) \
67 : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
68 return __res; \
69 }
71 #define QEMU_SYSCALL3(name,arg1,arg2,arg3) \
72 { \
73 long __res; \
74 __asm__ volatile ("int $0x80" \
75 : "=a" (__res) \
76 : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
77 "d" ((long)(arg3))); \
78 return __res; \
79 }
81 #define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \
82 { \
83 long __res; \
84 __asm__ volatile ("int $0x80" \
85 : "=a" (__res) \
86 : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
87 "d" ((long)(arg3)),"S" ((long)(arg4))); \
88 return __res; \
89 }
91 #define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \
92 { \
93 long __res; \
94 __asm__ volatile ("int $0x80" \
95 : "=a" (__res) \
96 : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
97 "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
98 return __res; \
99 }
101 #define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
102 { \
103 long __res; \
104 __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
105 : "=a" (__res) \
106 : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
107 "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
108 "0" ((long)(arg6))); \
109 return __res; \
110 }
112 int qemu_write(int fd, const void *buf, size_t n)
113 {
114 QEMU_SYSCALL3(write, fd, buf, n);
115 }
119 /****************************************************************/
120 /* shmat replacement */
122 int qemu_ipc(int call, unsigned long first,
123 unsigned long second, unsigned long third,
124 void *ptr, unsigned long fifth)
125 {
126 QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
127 }
129 #define SHMAT 21
131 /* we must define shmat so that a specific address will be used when
132 mapping the X11 ximage */
133 void *shmat(int shmid, const void *shmaddr, int shmflg)
134 {
135 void *ptr;
136 int ret;
137 /* we give an address in the right memory area */
138 if (!shmaddr)
139 shmaddr = get_mmap_addr(8192 * 1024);
140 ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0);
141 if (ret < 0)
142 return NULL;
143 return ptr;
144 }
146 /****************************************************************/
147 /* sigaction bypassing the threads */
149 static int kernel_sigaction(int signum, const struct qemu_sigaction *act,
150 struct qemu_sigaction *oldact,
151 int sigsetsize)
152 {
153 QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize);
154 }
156 int qemu_sigaction(int signum, const struct qemu_sigaction *act,
157 struct qemu_sigaction *oldact)
158 {
159 return kernel_sigaction(signum, act, oldact, 8);
160 }
162 /****************************************************************/
163 /* memory allocation */
165 //#define DEBUG_MALLOC
167 #define MALLOC_BASE 0xab000000
168 #define PHYS_RAM_BASE 0xac000000
170 #define MALLOC_ALIGN 16
171 #define BLOCK_HEADER_SIZE 16
173 typedef struct MemoryBlock {
174 struct MemoryBlock *next;
175 unsigned long size; /* size of block, including header */
176 } MemoryBlock;
178 static MemoryBlock *first_free_block;
179 static unsigned long malloc_addr = MALLOC_BASE;
181 static void *malloc_get_space(size_t size)
182 {
183 void *ptr;
184 size = TARGET_PAGE_ALIGN(size);
185 ptr = mmap((void *)malloc_addr, size,
186 PROT_WRITE | PROT_READ,
187 MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
188 if (ptr == MAP_FAILED)
189 return NULL;
190 malloc_addr += size;
191 return ptr;
192 }
194 void *qemu_malloc(size_t size)
195 {
196 MemoryBlock *mb, *mb1, **pmb;
197 void *ptr;
198 size_t size1, area_size;
200 if (size == 0)
201 return NULL;
203 size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1);
204 pmb = &first_free_block;
205 for(;;) {
206 mb = *pmb;
207 if (mb == NULL)
208 break;
209 if (size <= mb->size)
210 goto found;
211 pmb = &mb->next;
212 }
213 /* no big enough blocks found: get new space */
214 area_size = TARGET_PAGE_ALIGN(size);
215 mb = malloc_get_space(area_size);
216 if (!mb)
217 return NULL;
218 size1 = area_size - size;
219 if (size1 > 0) {
220 /* create a new free block */
221 mb1 = (MemoryBlock *)((uint8_t *)mb + size);
222 mb1->next = NULL;
223 mb1->size = size1;
224 *pmb = mb1;
225 }
226 goto the_end;
227 found:
228 /* a free block was found: use it */
229 size1 = mb->size - size;
230 if (size1 > 0) {
231 /* create a new free block */
232 mb1 = (MemoryBlock *)((uint8_t *)mb + size);
233 mb1->next = mb->next;
234 mb1->size = size1;
235 *pmb = mb1;
236 } else {
237 /* suppress the first block */
238 *pmb = mb->next;
239 }
240 the_end:
241 mb->size = size;
242 mb->next = NULL;
243 ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE);
244 #ifdef DEBUG_MALLOC
245 qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr);
246 #endif
247 return ptr;
248 }
250 void qemu_free(void *ptr)
251 {
252 MemoryBlock *mb;
254 if (!ptr)
255 return;
256 mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
257 mb->next = first_free_block;
258 first_free_block = mb;
259 }
261 /****************************************************************/
262 /* virtual memory allocation */
264 unsigned long mmap_addr = PHYS_RAM_BASE;
266 void *get_mmap_addr(unsigned long size)
267 {
268 unsigned long addr;
269 addr = mmap_addr;
270 mmap_addr += ((size + 4095) & ~4095) + 4096;
271 return (void *)addr;
272 }
274 #else
276 int qemu_write(int fd, const void *buf, size_t n)
277 {
278 int ret;
279 ret = write(fd, buf, n);
280 if (ret < 0)
281 return -errno;
282 else
283 return ret;
284 }
286 void *get_mmap_addr(unsigned long size)
287 {
288 return NULL;
289 }
291 void qemu_free(void *ptr)
292 {
293 free(ptr);
294 }
296 void *qemu_malloc(size_t size)
297 {
298 return malloc(size);
299 }
301 #endif
303 void *qemu_mallocz(size_t size)
304 {
305 void *ptr;
306 ptr = qemu_malloc(size);
307 if (!ptr)
308 return NULL;
309 memset(ptr, 0, size);
310 return ptr;
311 }
313 char *qemu_strdup(const char *str)
314 {
315 char *ptr;
316 ptr = qemu_malloc(strlen(str) + 1);
317 if (!ptr)
318 return NULL;
319 strcpy(ptr, str);
320 return ptr;
321 }
323 /****************************************************************/
324 /* printf support */
326 static inline int qemu_isdigit(int c)
327 {
328 return c >= '0' && c <= '9';
329 }
331 #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
333 /* from BSD ppp sources */
334 int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
335 {
336 int c, i, n;
337 int width, prec, fillch;
338 int base, len, neg;
339 unsigned long val = 0;
340 const char *f;
341 char *str, *buf0;
342 char num[32];
343 static const char hexchars[] = "0123456789abcdef";
345 buf0 = buf;
346 --buflen;
347 while (buflen > 0) {
348 for (f = fmt; *f != '%' && *f != 0; ++f)
349 ;
350 if (f > fmt) {
351 len = f - fmt;
352 if (len > buflen)
353 len = buflen;
354 memcpy(buf, fmt, len);
355 buf += len;
356 buflen -= len;
357 fmt = f;
358 }
359 if (*fmt == 0)
360 break;
361 c = *++fmt;
362 width = prec = 0;
363 fillch = ' ';
364 if (c == '0') {
365 fillch = '0';
366 c = *++fmt;
367 }
368 if (c == '*') {
369 width = va_arg(args, int);
370 c = *++fmt;
371 } else {
372 while (qemu_isdigit(c)) {
373 width = width * 10 + c - '0';
374 c = *++fmt;
375 }
376 }
377 if (c == '.') {
378 c = *++fmt;
379 if (c == '*') {
380 prec = va_arg(args, int);
381 c = *++fmt;
382 } else {
383 while (qemu_isdigit(c)) {
384 prec = prec * 10 + c - '0';
385 c = *++fmt;
386 }
387 }
388 }
389 /* modifiers */
390 switch(c) {
391 case 'l':
392 c = *++fmt;
393 break;
394 default:
395 break;
396 }
397 str = 0;
398 base = 0;
399 neg = 0;
400 ++fmt;
401 switch (c) {
402 case 'd':
403 i = va_arg(args, int);
404 if (i < 0) {
405 neg = 1;
406 val = -i;
407 } else
408 val = i;
409 base = 10;
410 break;
411 case 'o':
412 val = va_arg(args, unsigned int);
413 base = 8;
414 break;
415 case 'x':
416 case 'X':
417 val = va_arg(args, unsigned int);
418 base = 16;
419 break;
420 case 'p':
421 val = (unsigned long) va_arg(args, void *);
422 base = 16;
423 neg = 2;
424 break;
425 case 's':
426 str = va_arg(args, char *);
427 break;
428 case 'c':
429 num[0] = va_arg(args, int);
430 num[1] = 0;
431 str = num;
432 break;
433 default:
434 *buf++ = '%';
435 if (c != '%')
436 --fmt; /* so %z outputs %z etc. */
437 --buflen;
438 continue;
439 }
440 if (base != 0) {
441 str = num + sizeof(num);
442 *--str = 0;
443 while (str > num + neg) {
444 *--str = hexchars[val % base];
445 val = val / base;
446 if (--prec <= 0 && val == 0)
447 break;
448 }
449 switch (neg) {
450 case 1:
451 *--str = '-';
452 break;
453 case 2:
454 *--str = 'x';
455 *--str = '0';
456 break;
457 }
458 len = num + sizeof(num) - 1 - str;
459 } else {
460 len = strlen(str);
461 if (prec > 0 && len > prec)
462 len = prec;
463 }
464 if (width > 0) {
465 if (width > buflen)
466 width = buflen;
467 if ((n = width - len) > 0) {
468 buflen -= n;
469 for (; n > 0; --n)
470 *buf++ = fillch;
471 }
472 }
473 if (len > buflen)
474 len = buflen;
475 memcpy(buf, str, len);
476 buf += len;
477 buflen -= len;
478 }
479 *buf = 0;
480 return buf - buf0;
481 }
483 void qemu_vprintf(const char *fmt, va_list ap)
484 {
485 char buf[1024];
486 int len;
488 len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
489 qemu_write(1, buf, len);
490 }
492 void qemu_printf(const char *fmt, ...)
493 {
494 va_list ap;
495 va_start(ap, fmt);
496 qemu_vprintf(fmt, ap);
497 va_end(ap);
498 }