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