These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / target-lm32 / lm32-semi.c
1 /*
2  *  Lattice Mico32 semihosting syscall interface
3  *
4  *  Copyright (c) 2014 Michael Walle <michael@walle.cc>
5  *
6  * Based on target-m68k/m68k-semi.c, which is
7  *  Copyright (c) 2005-2007 CodeSourcery.
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  */
12
13 #include "qemu/osdep.h"
14 #include "cpu.h"
15 #include "exec/helper-proto.h"
16 #include "qemu/log.h"
17 #include "exec/softmmu-semi.h"
18
19 enum {
20     TARGET_SYS_exit    = 1,
21     TARGET_SYS_open    = 2,
22     TARGET_SYS_close   = 3,
23     TARGET_SYS_read    = 4,
24     TARGET_SYS_write   = 5,
25     TARGET_SYS_lseek   = 6,
26     TARGET_SYS_fstat   = 10,
27     TARGET_SYS_stat    = 15,
28 };
29
30 enum {
31     NEWLIB_O_RDONLY    =   0x0,
32     NEWLIB_O_WRONLY    =   0x1,
33     NEWLIB_O_RDWR      =   0x2,
34     NEWLIB_O_APPEND    =   0x8,
35     NEWLIB_O_CREAT     = 0x200,
36     NEWLIB_O_TRUNC     = 0x400,
37     NEWLIB_O_EXCL      = 0x800,
38 };
39
40 static int translate_openflags(int flags)
41 {
42     int hf;
43
44     if (flags & NEWLIB_O_WRONLY) {
45         hf = O_WRONLY;
46     } else if (flags & NEWLIB_O_RDWR) {
47         hf = O_RDWR;
48     } else {
49         hf = O_RDONLY;
50     }
51
52     if (flags & NEWLIB_O_APPEND) {
53         hf |= O_APPEND;
54     }
55
56     if (flags & NEWLIB_O_CREAT) {
57         hf |= O_CREAT;
58     }
59
60     if (flags & NEWLIB_O_TRUNC) {
61         hf |= O_TRUNC;
62     }
63
64     if (flags & NEWLIB_O_EXCL) {
65         hf |= O_EXCL;
66     }
67
68     return hf;
69 }
70
71 struct newlib_stat {
72     int16_t     newlib_st_dev;     /* device */
73     uint16_t    newlib_st_ino;     /* inode */
74     uint16_t    newlib_st_mode;    /* protection */
75     uint16_t    newlib_st_nlink;   /* number of hard links */
76     uint16_t    newlib_st_uid;     /* user ID of owner */
77     uint16_t    newlib_st_gid;     /* group ID of owner */
78     int16_t     newlib_st_rdev;    /* device type (if inode device) */
79     int32_t     newlib_st_size;    /* total size, in bytes */
80     int32_t     newlib_st_atime;   /* time of last access */
81     uint32_t    newlib_st_spare1;
82     int32_t     newlib_st_mtime;   /* time of last modification */
83     uint32_t    newlib_st_spare2;
84     int32_t     newlib_st_ctime;   /* time of last change */
85     uint32_t    newlib_st_spare3;
86 } QEMU_PACKED;
87
88 static int translate_stat(CPULM32State *env, target_ulong addr,
89         struct stat *s)
90 {
91     struct newlib_stat *p;
92
93     p = lock_user(VERIFY_WRITE, addr, sizeof(struct newlib_stat), 0);
94     if (!p) {
95         return 0;
96     }
97     p->newlib_st_dev = cpu_to_be16(s->st_dev);
98     p->newlib_st_ino = cpu_to_be16(s->st_ino);
99     p->newlib_st_mode = cpu_to_be16(s->st_mode);
100     p->newlib_st_nlink = cpu_to_be16(s->st_nlink);
101     p->newlib_st_uid = cpu_to_be16(s->st_uid);
102     p->newlib_st_gid = cpu_to_be16(s->st_gid);
103     p->newlib_st_rdev = cpu_to_be16(s->st_rdev);
104     p->newlib_st_size = cpu_to_be32(s->st_size);
105     p->newlib_st_atime = cpu_to_be32(s->st_atime);
106     p->newlib_st_mtime = cpu_to_be32(s->st_mtime);
107     p->newlib_st_ctime = cpu_to_be32(s->st_ctime);
108     unlock_user(p, addr, sizeof(struct newlib_stat));
109
110     return 1;
111 }
112
113 bool lm32_cpu_do_semihosting(CPUState *cs)
114 {
115     LM32CPU *cpu = LM32_CPU(cs);
116     CPULM32State *env = &cpu->env;
117
118     int ret = -1;
119     target_ulong nr, arg0, arg1, arg2;
120     void *p;
121     struct stat s;
122
123     nr = env->regs[R_R8];
124     arg0 = env->regs[R_R1];
125     arg1 = env->regs[R_R2];
126     arg2 = env->regs[R_R3];
127
128     switch (nr) {
129     case TARGET_SYS_exit:
130         /* void _exit(int rc) */
131         exit(arg0);
132
133     case TARGET_SYS_open:
134         /* int open(const char *pathname, int flags) */
135         p = lock_user_string(arg0);
136         if (!p) {
137             ret = -1;
138         } else {
139             ret = open(p, translate_openflags(arg2));
140             unlock_user(p, arg0, 0);
141         }
142         break;
143
144     case TARGET_SYS_read:
145         /* ssize_t read(int fd, const void *buf, size_t count) */
146         p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
147         if (!p) {
148             ret = -1;
149         } else {
150             ret = read(arg0, p, arg2);
151             unlock_user(p, arg1, arg2);
152         }
153         break;
154
155     case TARGET_SYS_write:
156         /* ssize_t write(int fd, const void *buf, size_t count) */
157         p = lock_user(VERIFY_READ, arg1, arg2, 1);
158         if (!p) {
159             ret = -1;
160         } else {
161             ret = write(arg0, p, arg2);
162             unlock_user(p, arg1, 0);
163         }
164         break;
165
166     case TARGET_SYS_close:
167         /* int close(int fd) */
168         /* don't close stdin/stdout/stderr */
169         if (arg0 > 2) {
170             ret = close(arg0);
171         } else {
172             ret = 0;
173         }
174         break;
175
176     case TARGET_SYS_lseek:
177         /* off_t lseek(int fd, off_t offset, int whence */
178         ret = lseek(arg0, arg1, arg2);
179         break;
180
181     case TARGET_SYS_stat:
182         /* int stat(const char *path, struct stat *buf) */
183         p = lock_user_string(arg0);
184         if (!p) {
185             ret = -1;
186         } else {
187             ret = stat(p, &s);
188             unlock_user(p, arg0, 0);
189             if (translate_stat(env, arg1, &s) == 0) {
190                 ret = -1;
191             }
192         }
193         break;
194
195     case TARGET_SYS_fstat:
196         /* int stat(int fd, struct stat *buf) */
197         ret = fstat(arg0, &s);
198         if (ret == 0) {
199             if (translate_stat(env, arg1, &s) == 0) {
200                 ret = -1;
201             }
202         }
203         break;
204
205     default:
206         /* unhandled */
207         return false;
208     }
209
210     env->regs[R_R1] = ret;
211     return true;
212 }