Revision a87295e8

b/Makefile.target
468 468
endif
469 469
ifeq ($(TARGET_BASE_ARCH), m68k)
470 470
VL_OBJS+= an5206.o mcf5206.o ptimer.o
471
VL_OBJS+= m68k-semi.o
471 472
endif
472 473
ifdef CONFIG_GDBSTUB
473 474
VL_OBJS+=gdbstub.o 
b/arm-semi.c
112 112
    return code;
113 113
}
114 114

  
115
static uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
116
{
117
    uint32_t val;
118

  
119
    cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
120
    return tswap32(val);
121
}
122
static uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
123
{
124
    uint8_t val;
125

  
126
    cpu_memory_rw_debug(env, addr, &val, 1, 0);
127
    return val;
128
}
129
#define tget32(p) softmmu_tget32(env, p)
130
#define tget8(p) softmmu_tget8(env, p)
131

  
132
static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
133
                               int copy)
134
{
135
    char *p;
136
    /* TODO: Make this something that isn't fixed size.  */
137
    p = malloc(len);
138
    if (copy)
139
        cpu_memory_rw_debug(env, addr, p, len, 0);
140
    return p;
141
}
142
#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
143
static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
144
{
145
    char *p;
146
    char *s;
147
    uint8_t c;
148
    /* TODO: Make this something that isn't fixed size.  */
149
    s = p = malloc(1024);
150
    do {
151
        cpu_memory_rw_debug(env, addr, &c, 1, 0);
152
        addr++;
153
        *(p++) = c;
154
    } while (c);
155
    return s;
156
}
157
#define lock_user_string(p) softmmu_lock_user_string(env, p)
158
static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
159
                                target_ulong len)
160
{
161
    if (len)
162
        cpu_memory_rw_debug(env, addr, p, len, 1);
163
    free(p);
164
}
165
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
115
#include "softmmu-semi.h"
166 116
#endif
167 117

  
168 118
static target_ulong arm_semi_syscall_len;
b/gdbstub.c
963 963

  
964 964
/* Send a gdb syscall request.
965 965
   This accepts limited printf-style format specifiers, specifically:
966
    %x - target_ulong argument printed in hex.
967
    %s - string pointer (target_ulong) and length (int) pair.  */
966
    %x  - target_ulong argument printed in hex.
967
    %lx - 64-bit argument printed in hex.
968
    %s  - string pointer (target_ulong) and length (int) pair.  */
968 969
void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...)
969 970
{
970 971
    va_list va;
971 972
    char buf[256];
972 973
    char *p;
973 974
    target_ulong addr;
975
    uint64_t i64;
974 976
    GDBState *s;
975 977

  
976 978
    s = gdb_syscall_state;
......
993 995
                addr = va_arg(va, target_ulong);
994 996
                p += sprintf(p, TARGET_FMT_lx, addr);
995 997
                break;
998
            case 'l':
999
                if (*(fmt++) != 'x')
1000
                    goto bad_format;
1001
                i64 = va_arg(va, uint64_t);
1002
                p += sprintf(p, "%" PRIx64, i64);
1003
                break;
996 1004
            case 's':
997 1005
                addr = va_arg(va, target_ulong);
998 1006
                p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int));
999 1007
                break;
1000 1008
            default:
1009
            bad_format:
1001 1010
                fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n",
1002 1011
                        fmt - 1);
1003 1012
                break;
/dev/null
1
/*
2
 *  m68k/ColdFire Semihosting ssycall interface
3
 * 
4
 *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 */
20

  
21
#include <sys/types.h>
22
#include <sys/stat.h>
23
#include <errno.h>
24
#include <fcntl.h>
25
#include <unistd.h>
26
#include <stdlib.h>
27
#include <stdio.h>
28
#include <sys/time.h>
29
#include <time.h>
30

  
31
#include "qemu.h"
32

  
33
#define HOSTED_EXIT  0
34
#define HOSTED_PUTCHAR 1 /* Obsolete */
35
#define HOSTED_OPEN 2
36
#define HOSTED_CLOSE 3
37
#define HOSTED_READ 4
38
#define HOSTED_WRITE 5
39
#define HOSTED_LSEEK 6
40
#define HOSTED_RENAME 7
41
#define HOSTED_UNLINK 8
42
#define HOSTED_STAT 9
43
#define HOSTED_FSTAT 10
44
#define HOSTED_GETTIMEOFDAY 11
45
#define HOSTED_ISATTY 12
46
#define HOSTED_SYSTEM 13
47

  
48
typedef uint32_t gdb_mode_t;
49
typedef uint32_t gdb_time_t;
50

  
51
struct m68k_gdb_stat {
52
  uint32_t    gdb_st_dev;     /* device */
53
  uint32_t    gdb_st_ino;     /* inode */
54
  gdb_mode_t  gdb_st_mode;    /* protection */
55
  uint32_t    gdb_st_nlink;   /* number of hard links */
56
  uint32_t    gdb_st_uid;     /* user ID of owner */
57
  uint32_t    gdb_st_gid;     /* group ID of owner */
58
  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
59
  uint64_t    gdb_st_size;    /* total size, in bytes */
60
  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
61
  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
62
  gdb_time_t  gdb_st_atime;   /* time of last access */
63
  gdb_time_t  gdb_st_mtime;   /* time of last modification */
64
  gdb_time_t  gdb_st_ctime;   /* time of last change */
65
};
66

  
67
struct gdb_timeval {
68
  gdb_time_t tv_sec;  /* second */
69
  uint64_t tv_usec;   /* microsecond */
70
};
71

  
72
#define GDB_O_RDONLY   0x0
73
#define GDB_O_WRONLY   0x1
74
#define GDB_O_RDWR     0x2
75
#define GDB_O_APPEND   0x8
76
#define GDB_O_CREAT  0x200
77
#define GDB_O_TRUNC  0x400
78
#define GDB_O_EXCL   0x800
79

  
80
static int translate_openflags(int flags)
81
{
82
    int hf;
83

  
84
    if (flags & GDB_O_WRONLY)
85
        hf = O_WRONLY;
86
    else if (flags & GDB_O_RDWR)
87
        hf = O_RDWR;
88
    else
89
        hf = O_RDONLY;
90

  
91
    if (flags & GDB_O_APPEND) hf |= O_APPEND;
92
    if (flags & GDB_O_CREAT) hf |= O_CREAT;
93
    if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
94
    if (flags & GDB_O_EXCL) hf |= O_EXCL;
95

  
96
    return hf;
97
}
98

  
99
static void translate_stat(struct m68k_gdb_stat *p, struct stat *s)
100
{
101
    p->gdb_st_dev = tswap16(s->st_dev);
102
    p->gdb_st_ino = tswap16(s->st_ino);
103
    p->gdb_st_mode = tswap32(s->st_mode);
104
    p->gdb_st_nlink = tswap16(s->st_nlink);
105
    p->gdb_st_uid = tswap16(s->st_uid);
106
    p->gdb_st_gid = tswap16(s->st_gid);
107
    p->gdb_st_rdev = tswap16(s->st_rdev);
108
    p->gdb_st_size = tswap32(s->st_size);
109
    p->gdb_st_atime = tswap32(s->st_atime);
110
    p->gdb_st_mtime = tswap32(s->st_mtime);
111
    p->gdb_st_ctime = tswap32(s->st_ctime);
112
    p->gdb_st_blksize = tswap32(s->st_blksize);
113
    p->gdb_st_blocks = tswap32(s->st_blocks);
114
}
115

  
116
static inline uint32_t check_err(CPUM68KState *env, uint32_t code)
117
{
118
  if (code == (uint32_t)-1) {
119
      env->sr |= CCF_C;
120
  } else {
121
      env->sr &= ~CCF_C;
122
      env->dregs[0] = code;
123
  }
124
  return code;
125
}
126

  
127
#define ARG(x) tswap32(args[x])
128
void do_m68k_semihosting(CPUM68KState *env, int nr)
129
{
130
    uint32_t *args;
131

  
132
    args = (uint32_t *)env->dregs[1];
133
    switch (nr) {
134
    case HOSTED_EXIT:
135
        exit(env->dregs[0]);
136
    case HOSTED_OPEN:
137
        /* Assume name is NULL terminated.  */
138
        check_err(env, open((char *)ARG(0), translate_openflags(ARG(2)),
139
                            ARG(3)));
140
        break;
141
    case HOSTED_CLOSE:
142
        {
143
            /* Ignore attempts to close stdin/out/err.  */
144
            int fd = ARG(0);
145
            if (fd > 2)
146
              check_err(env, close(fd));
147
            else
148
              check_err(env, 0);
149
            break;
150
        }
151
    case HOSTED_READ:
152
        check_err(env, read(ARG(0), (void *)ARG(1), ARG(2)));
153
        break;
154
    case HOSTED_WRITE:
155
        check_err(env, write(ARG(0), (void *)ARG(1), ARG(2)));
156
        break;
157
    case HOSTED_LSEEK:
158
        {
159
            uint64_t off;
160
            off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32);
161
            check_err(env, lseek(ARG(0), off, ARG(3)));
162
        }
163
        break;
164
    case HOSTED_RENAME:
165
        /* Assume names are NULL terminated.  */
166
        check_err(env, rename((char *)ARG(0), (char *)ARG(2)));
167
        break;
168
    case HOSTED_UNLINK:
169
        /* Assume name is NULL terminated.  */
170
        check_err(env, unlink((char *)ARG(0)));
171
        break;
172
    case HOSTED_STAT:
173
        /* Assume name is NULL terminated.  */
174
        {
175
            struct stat s;
176
            int rc;
177
            rc = check_err(env, stat((char *)ARG(0), &s));
178
            if (rc == 0) {
179
                translate_stat((struct m68k_gdb_stat *)ARG(2), &s);
180
            }
181
        }
182
        break;
183
    case HOSTED_FSTAT:
184
        {
185
            struct stat s;
186
            int rc;
187
            rc = check_err(env, fstat(ARG(0), &s));
188
            if (rc == 0) {
189
                translate_stat((struct m68k_gdb_stat *)ARG(1), &s);
190
            }
191
        }
192
        break;
193
    case HOSTED_GETTIMEOFDAY:
194
        {
195
            struct timeval tv;
196
            struct gdb_timeval *p;
197
            int rc;
198
            rc = check_err(env, gettimeofday(&tv, NULL));
199
            if (rc != 0) {
200
                p = (struct gdb_timeval *)ARG(0);
201
                p->tv_sec = tswap32(tv.tv_sec);
202
                p->tv_usec = tswap64(tv.tv_usec);
203
            }
204
        }
205
        break;
206
    case HOSTED_ISATTY:
207
        check_err(env, isatty(ARG(0)));
208
        break;
209
    case HOSTED_SYSTEM:
210
        /* Assume name is NULL terminated.  */
211
        check_err(env, system((char *)ARG(0)));
212
        break;
213
    default:
214
        cpu_abort(env, "Unsupported semihosting syscall %d\n", nr);
215
    }
216
}
b/linux-user/main.c
1502 1502
                }
1503 1503
            }
1504 1504
            break;
1505
        case EXCP_HALTED:
1505
        case EXCP_HALT_INSN:
1506 1506
            /* Semihosing syscall.  */
1507
            env->pc += 2;
1507
            env->pc += 4;
1508 1508
            do_m68k_semihosting(env, env->dregs[0]);
1509 1509
            break;
1510 1510
        case EXCP_LINEA:
......
1918 1918
        for(i = 0; i < 16; i++) {
1919 1919
            env->regs[i] = regs->uregs[i];
1920 1920
        }
1921
        ts->stack_base = info->start_stack;
1922
        ts->heap_base = info->brk;
1923
        /* This will be filled in on the first SYS_HEAPINFO call.  */
1924
        ts->heap_limit = 0;
1925 1921
    }
1926 1922
#elif defined(TARGET_SPARC)
1927 1923
    {
......
2049 2045
#error unsupported target CPU
2050 2046
#endif
2051 2047

  
2048
#if defined(TARGET_ARM) || defined(TARGET_M68K)
2049
    ts->stack_base = info->start_stack;
2050
    ts->heap_base = info->brk;
2051
    /* This will be filled in on the first SYS_HEAPINFO call.  */
2052
    ts->heap_limit = 0;
2053
#endif
2054

  
2052 2055
    if (gdbstub_port) {
2053 2056
        gdbserver_start (gdbstub_port);
2054 2057
        gdb_handlesig(env, 0);
b/linux-user/qemu.h
62 62
#ifdef TARGET_ARM
63 63
    /* FPA state */
64 64
    FPA11 fpa;
65
    /* Extra fields for semihosted binaries.  */
66
    uint32_t stack_base;
67
    uint32_t heap_base;
68
    uint32_t heap_limit;
69 65
    int swi_errno;
70 66
#endif
71 67
#if defined(TARGET_I386) && !defined(TARGET_X86_64)
......
78 74
#ifdef TARGET_M68K
79 75
    int sim_syscalls;
80 76
#endif
77
#if defined(TARGET_ARM) || defined(TARGET_M68K)
78
    /* Extra fields for semihosted binaries.  */
79
    uint32_t stack_base;
80
    uint32_t heap_base;
81
    uint32_t heap_limit;
82
#endif
81 83
    int used; /* non zero if used */
82 84
    struct image_info *info;
83 85
    uint8_t stack[0];
b/m68k-semi.c
1
/*
2
 *  m68k/ColdFire Semihosting syscall interface
3
 * 
4
 *  Copyright (c) 2005-2007 CodeSourcery.
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 */
20

  
21
#include <sys/types.h>
22
#include <sys/stat.h>
23
#include <errno.h>
24
#include <fcntl.h>
25
#include <unistd.h>
26
#include <stdlib.h>
27
#include <stdio.h>
28
#include <sys/time.h>
29
#include <time.h>
30

  
31
#include "cpu.h"
32
#if defined(CONFIG_USER_ONLY)
33
#include "qemu.h"
34
#define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
35
#else
36
#include "vl.h"
37
#include "softmmu-semi.h"
38
#endif
39

  
40
#define HOSTED_EXIT  0
41
#define HOSTED_INIT_SIM 1
42
#define HOSTED_OPEN 2
43
#define HOSTED_CLOSE 3
44
#define HOSTED_READ 4
45
#define HOSTED_WRITE 5
46
#define HOSTED_LSEEK 6
47
#define HOSTED_RENAME 7
48
#define HOSTED_UNLINK 8
49
#define HOSTED_STAT 9
50
#define HOSTED_FSTAT 10
51
#define HOSTED_GETTIMEOFDAY 11
52
#define HOSTED_ISATTY 12
53
#define HOSTED_SYSTEM 13
54

  
55
typedef uint32_t gdb_mode_t;
56
typedef uint32_t gdb_time_t;
57

  
58
struct m68k_gdb_stat {
59
  uint32_t    gdb_st_dev;     /* device */
60
  uint32_t    gdb_st_ino;     /* inode */
61
  gdb_mode_t  gdb_st_mode;    /* protection */
62
  uint32_t    gdb_st_nlink;   /* number of hard links */
63
  uint32_t    gdb_st_uid;     /* user ID of owner */
64
  uint32_t    gdb_st_gid;     /* group ID of owner */
65
  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
66
  uint64_t    gdb_st_size;    /* total size, in bytes */
67
  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
68
  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
69
  gdb_time_t  gdb_st_atime;   /* time of last access */
70
  gdb_time_t  gdb_st_mtime;   /* time of last modification */
71
  gdb_time_t  gdb_st_ctime;   /* time of last change */
72
} __attribute__((packed));
73

  
74
struct gdb_timeval {
75
  gdb_time_t tv_sec;  /* second */
76
  uint64_t tv_usec;   /* microsecond */
77
} __attribute__((packed));
78

  
79
#define GDB_O_RDONLY   0x0
80
#define GDB_O_WRONLY   0x1
81
#define GDB_O_RDWR     0x2
82
#define GDB_O_APPEND   0x8
83
#define GDB_O_CREAT  0x200
84
#define GDB_O_TRUNC  0x400
85
#define GDB_O_EXCL   0x800
86

  
87
static int translate_openflags(int flags)
88
{
89
    int hf;
90

  
91
    if (flags & GDB_O_WRONLY)
92
        hf = O_WRONLY;
93
    else if (flags & GDB_O_RDWR)
94
        hf = O_RDWR;
95
    else
96
        hf = O_RDONLY;
97

  
98
    if (flags & GDB_O_APPEND) hf |= O_APPEND;
99
    if (flags & GDB_O_CREAT) hf |= O_CREAT;
100
    if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
101
    if (flags & GDB_O_EXCL) hf |= O_EXCL;
102

  
103
    return hf;
104
}
105

  
106
static void translate_stat(CPUState *env, target_ulong addr, struct stat *s)
107
{
108
    struct m68k_gdb_stat *p;
109

  
110
    p = lock_user(addr, sizeof(struct m68k_gdb_stat), 0);
111
    p->gdb_st_dev = cpu_to_be32(s->st_dev);
112
    p->gdb_st_ino = cpu_to_be32(s->st_ino);
113
    p->gdb_st_mode = cpu_to_be32(s->st_mode);
114
    p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
115
    p->gdb_st_uid = cpu_to_be32(s->st_uid);
116
    p->gdb_st_gid = cpu_to_be32(s->st_gid);
117
    p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
118
    p->gdb_st_size = cpu_to_be64(s->st_size);
119
    p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
120
    p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
121
    p->gdb_st_atime = cpu_to_be32(s->st_atime);
122
    p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
123
    p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
124
    unlock_user(p, addr, sizeof(struct m68k_gdb_stat));
125
}
126

  
127
static int m68k_semi_is_fseek;
128

  
129
static void m68k_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
130
{
131
    target_ulong args;
132

  
133
    args = env->dregs[1];
134
    if (m68k_semi_is_fseek) {
135
        /* FIXME: We've already lost the high bits of the fseek
136
           return value.  */
137
        tput32(args, 0);
138
        args += 4;
139
        m68k_semi_is_fseek = 0;
140
    }
141
    tput32(args, ret);
142
    tput32(args + 4, errno);
143
}
144

  
145
#define ARG(x) tget32(args + (x) * 4)
146
#define PARG(x) ((unsigned long)ARG(x))
147
void do_m68k_semihosting(CPUM68KState *env, int nr)
148
{
149
    uint32_t args;
150
    void *p;
151
    void *q;
152
    uint32_t len;
153
    uint32_t result;
154

  
155
    args = env->dregs[1];
156
    switch (nr) {
157
    case HOSTED_EXIT:
158
        exit(env->dregs[0]);
159
    case HOSTED_OPEN:
160
        if (use_gdb_syscalls()) {
161
            gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", ARG(0), (int)ARG(1),
162
                           ARG(2), ARG(3));
163
            return;
164
        } else {
165
            p = lock_user_string(ARG(0));
166
            result = open(p, translate_openflags(ARG(2)), ARG(3));
167
            unlock_user(p, ARG(0), 0);
168
        }
169
        break;
170
    case HOSTED_CLOSE:
171
        {
172
            /* Ignore attempts to close stdin/out/err.  */
173
            int fd = ARG(0);
174
            if (fd > 2) {
175
                if (use_gdb_syscalls()) {
176
                    gdb_do_syscall(m68k_semi_cb, "close,%x", ARG(0));
177
                    return;
178
                } else {
179
                    result = close(fd);
180
                }
181
            } else {
182
                result = 0;
183
            }
184
            break;
185
        }
186
    case HOSTED_READ:
187
        len = ARG(2);
188
        if (use_gdb_syscalls()) {
189
            gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x",
190
                           ARG(0), ARG(1), len);
191
            return;
192
        } else {
193
            p = lock_user(ARG(1), len, 0);
194
            result = read(ARG(0), p, len);
195
            unlock_user(p, ARG(1), len);
196
        }
197
        break;
198
    case HOSTED_WRITE:
199
        len = ARG(2);
200
        if (use_gdb_syscalls()) {
201
            gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x",
202
                           ARG(0), ARG(1), len);
203
            return;
204
        } else {
205
            p = lock_user(ARG(1), len, 1);
206
            result = write(ARG(0), p, len);
207
            unlock_user(p, ARG(0), 0);
208
        }
209
        break;
210
    case HOSTED_LSEEK:
211
        {
212
            uint64_t off;
213
            off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32);
214
            if (use_gdb_syscalls()) {
215
                m68k_semi_is_fseek = 1;
216
                gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x",
217
                               ARG(0), off, ARG(3));
218
            } else {
219
                off = lseek(ARG(0), off, ARG(3));
220
                tput32(args, off >> 32);
221
                tput32(args + 4, off);
222
                tput32(args + 8, errno);
223
            }
224
            return;
225
        }
226
    case HOSTED_RENAME:
227
        if (use_gdb_syscalls()) {
228
            gdb_do_syscall(m68k_semi_cb, "rename,%s,%s", 
229
                           ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
230
            return;
231
        } else {
232
            p = lock_user_string(ARG(0));
233
            q = lock_user_string(ARG(2));
234
            result = rename(p, q);
235
            unlock_user(p, ARG(0), 0);
236
            unlock_user(q, ARG(2), 0);
237
        }
238
        break;
239
    case HOSTED_UNLINK:
240
        if (use_gdb_syscalls()) {
241
            gdb_do_syscall(m68k_semi_cb, "unlink,%s",
242
                           ARG(0), (int)ARG(1));
243
            return;
244
        } else {
245
            p = lock_user_string(ARG(0));
246
            result = unlink(p);
247
            unlock_user(p, ARG(0), 0);
248
        }
249
        break;
250
    case HOSTED_STAT:
251
        if (use_gdb_syscalls()) {
252
            gdb_do_syscall(m68k_semi_cb, "stat,%s,%x",
253
                           ARG(0), (int)ARG(1), ARG(2));
254
            return;
255
        } else {
256
            struct stat s;
257
            p = lock_user_string(ARG(0));
258
            result = stat(p, &s);
259
            unlock_user(p, ARG(0), 0);
260
            if (result == 0) {
261
                translate_stat(env, ARG(2), &s);
262
            }
263
        }
264
        break;
265
    case HOSTED_FSTAT:
266
        if (use_gdb_syscalls()) {
267
            gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x",
268
                           ARG(0), ARG(1));
269
            return;
270
        } else {
271
            struct stat s;
272
            result = fstat(ARG(0), &s);
273
            if (result == 0) {
274
                translate_stat(env, ARG(1), &s);
275
            }
276
        }
277
        break;
278
    case HOSTED_GETTIMEOFDAY:
279
        if (use_gdb_syscalls()) {
280
            gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x",
281
                           ARG(0), ARG(1));
282
            return;
283
        } else {
284
            struct timeval tv;
285
            struct gdb_timeval *p;
286
            result = gettimeofday(&tv, NULL);
287
            if (result != 0) {
288
                p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0);
289
                p->tv_sec = cpu_to_be32(tv.tv_sec);
290
                p->tv_usec = cpu_to_be64(tv.tv_usec);
291
                unlock_user(p, ARG(0), sizeof(struct gdb_timeval));
292
            }
293
        }
294
        break;
295
    case HOSTED_ISATTY:
296
        if (use_gdb_syscalls()) {
297
            gdb_do_syscall(m68k_semi_cb, "isatty,%x", ARG(0));
298
            return;
299
        } else {
300
            result = isatty(ARG(0));
301
        }
302
        break;
303
    case HOSTED_SYSTEM:
304
        if (use_gdb_syscalls()) {
305
            gdb_do_syscall(m68k_semi_cb, "system,%s",
306
                           ARG(0), (int)ARG(1));
307
            return;
308
        } else {
309
            p = lock_user_string(ARG(0));
310
            result = system(p);
311
            unlock_user(p, ARG(0), 0);
312
        }
313
        break;
314
    case HOSTED_INIT_SIM:
315
#if defined(CONFIG_USER_ONLY)
316
        {
317
        TaskState *ts = env->opaque;
318
        /* Allocate the heap using sbrk.  */
319
        if (!ts->heap_limit) {
320
            long ret;
321
            uint32_t size;
322
            uint32_t base;
323

  
324
            base = do_brk(0);
325
            size = SEMIHOSTING_HEAP_SIZE;
326
            /* Try a big heap, and reduce the size if that fails.  */
327
            for (;;) {
328
                ret = do_brk(base + size);
329
                if (ret != -1)
330
                    break;
331
                size >>= 1;
332
            }
333
            ts->heap_limit = base + size;
334
        }
335
        /* This call may happen before we have writable memory, so return
336
           values directly in registers.  */
337
        env->dregs[1] = ts->heap_limit;
338
        env->aregs[7] = ts->stack_base;
339
        }
340
#else
341
        /* FIXME: This is wrong for boards where RAM does not start at
342
           address zero.  */
343
        env->dregs[1] = ram_size;
344
        env->aregs[7] = ram_size;
345
#endif
346
        return;
347
    default:
348
        cpu_abort(env, "Unsupported semihosting syscall %d\n", nr);
349
        result = 0;
350
    }
351
    tput32(args, result);
352
    tput32(args + 4, errno);
353
}
b/qemu-doc.texi
715 715
Start right away with a saved state (@code{loadvm} in monitor)
716 716

  
717 717
@item -semihosting
718
Enable "Angel" semihosting interface (ARM target machines only).
718
Enable semihosting syscall emulation (ARM and M68K target machines only).
719

  
720
On ARM this implements the "Angel" interface.
721
On M68K this implements the "ColdFire GDB" interface used by libgloss.
722

  
719 723
Note that this allows guest direct access to the host filesystem,
720 724
so should only be used with trusted guest OS.
721 725
@end table
b/target-m68k/cpu.h
51 51
#define EXCP_ICE            13
52 52

  
53 53
#define EXCP_RTE            0x100
54
#define EXCP_HALT_INSN      0x101
54 55

  
55 56
typedef struct CPUM68KState {
56 57
    uint32_t dregs[8];
......
148 149

  
149 150
#define M68K_FPCR_PREC (1 << 6)
150 151

  
152
void do_m68k_semihosting(CPUM68KState *env, int nr);
153

  
151 154
#ifdef CONFIG_USER_ONLY
152 155
/* Linux uses 8k pages.  */
153 156
#define TARGET_PAGE_BITS 13
b/target-m68k/op.c
383 383
    FORCE_RET();
384 384
}
385 385

  
386
/* Halt is special because it may be a semihosting call.  */
386 387
OP(halt)
387 388
{
389
    RAISE_EXCEPTION(EXCP_HALT_INSN);
390
    FORCE_RET();
391
}
392

  
393
OP(stop)
394
{
388 395
    env->halted = 1;
389 396
    RAISE_EXCEPTION(EXCP_HLT);
390 397
    FORCE_RET();
b/target-m68k/op_helper.c
28 28

  
29 29
#else
30 30

  
31
extern int semihosting_enabled;
32

  
31 33
#define MMUSUFFIX _mmu
32 34
#define GETPC() (__builtin_return_address(0))
33 35

  
......
104 106
            /* Return from an exception.  */
105 107
            do_rte();
106 108
            return;
109
        case EXCP_HALT_INSN:
110
            if (semihosting_enabled
111
                    && (env->sr & SR_S) != 0
112
                    && (env->pc & 3) == 0
113
                    && lduw_code(env->pc - 4) == 0x4e71
114
                    && ldl_code(env->pc) == 0x4e7bf000) {
115
                env->pc += 4;
116
                do_m68k_semihosting(env, env->dregs[0]);
117
                return;
118
            }
119
            env->halted = 1;
120
            env->exception_index = EXCP_HLT;
121
            cpu_loop_exit();
122
            return;
107 123
        }
108 124
        if (env->exception_index >= EXCP_TRAP0
109 125
            && env->exception_index <= EXCP_TRAP15) {
b/target-m68k/translate.c
1901 1901

  
1902 1902
DISAS_INSN(halt)
1903 1903
{
1904
    gen_flush_cc_op(s);
1905 1904
    gen_jmp(s, gen_im32(s->pc));
1906 1905
    gen_op_halt();
1907 1906
}
......
1919 1918
    s->pc += 2;
1920 1919

  
1921 1920
    gen_set_sr_im(s, ext, 0);
1922
    disas_halt(s, insn);
1921
    gen_jmp(s, gen_im32(s->pc));
1922
    gen_op_stop();
1923 1923
}
1924 1924

  
1925 1925
DISAS_INSN(rte)
b/vl.c
6865 6865
    { "show-cursor", 0, QEMU_OPTION_show_cursor },
6866 6866
    { "daemonize", 0, QEMU_OPTION_daemonize },
6867 6867
    { "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
6868
#if defined(TARGET_ARM)
6868
#if defined(TARGET_ARM) || defined(TARGET_M68K)
6869 6869
    { "semihosting", 0, QEMU_OPTION_semihosting },
6870 6870
#endif
6871 6871
    { "name", HAS_ARG, QEMU_OPTION_name },

Also available in: Unified diff