forked from rumpkernel-attic/rumpuser-linuxkernel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhypervisor.c
190 lines (154 loc) · 3.41 KB
/
hypervisor.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
* Copyright (c) 2013 Antti Kantee
*
* See LICENSE
*
* This module contains the very basic hypercalls you need to
* run a rump kernel.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <rump/rumpuser.h>
#include "hypervisor.h"
struct rumpuser_hyperup rumpuser__hyp;
static struct mutex printmtx;
int
rumpuser_init(int version, const struct rumpuser_hyperup *hyp)
{
if (version != 17)
return 1; /* EKERNELMISMATCH */
mutex_init(&printmtx);
rumpuser__thrinit();
rumpuser__hyp = *hyp;
return 0;
}
void
rumpuser_putchar(int ch)
{
static char buf[1024];
static unsigned int bufptr = 0;
mutex_lock(&printmtx);
if (ch != '\n' && bufptr != sizeof(buf)-1) {
buf[bufptr++] = (char)ch;
} else {
buf[bufptr] = '\0';
printk(KERN_INFO "%s\n", buf);
bufptr = 0;
}
mutex_unlock(&printmtx);
}
void
rumpuser_dprintf(const char *fmt, ...)
{
va_list ap;
int rv;
va_start(ap, fmt);
rv = vprintk(fmt, ap);
va_end(ap);
}
int
rumpuser_malloc(size_t len, int alignment, void **retval)
{
void *rv;
/*
* Yea, uh, should allocate with proper alignment, not hope
* that we get some. is there an allocator in the linux kernel
* which takes alignment as a parameter?
*/
rv = kmalloc(len, GFP_KERNEL);
BUG_ON(alignment && ((uintptr_t)rv & (uintptr_t)(alignment-1)));
*retval = rv;
return rv ? 0 : ENOMEM;
}
void
rumpuser_free(void *addr, size_t len)
{
kfree(addr);
}
void
rumpuser_exit(int how)
{
dump_stack();
/* sleep forever, sometimes prevents hangs before debugging */
printk(KERN_INFO "elvis has NOT left the building!\n");
set_current_state(TASK_INTERRUPTIBLE);
for (;;)
schedule_timeout(MAX_SCHEDULE_TIMEOUT);
}
/* the environment is a bit more hardcoded than in a userspace hypervisor */
static struct {
const char *name;
const char *value;
} envtab[] = {
{ RUMPUSER_PARAM_NCPU, "4" }, /* default to 4 CPUs ... just for fun */
{ RUMPUSER_PARAM_HOSTNAME, "rump-in-the-kernel" },
{ "RUMP_VERBOSE", "1" },
{ NULL, NULL },
};
int
rumpuser_getparam(const char *name, void *buf, size_t blen)
{
int i;
for (i = 0; envtab[i].name; i++) {
if (strcmp(name, envtab[i].name) == 0) {
if (blen < strlen(envtab[i].value)+1) {
return 11;
} else {
strcpy(buf, envtab[i].value);
return 0;
}
}
}
return 37;
}
int
rumpuser_clock_gettime(int enum_rumpclock, int64_t *sec, long *nsec)
{
struct timespec ts;
ts = current_kernel_time();
*sec = ts.tv_sec;
*nsec = ts.tv_nsec;
return 0;
}
/* hmm, is there an absolute sleep in the linux kernel? */
int
rumpuser_clock_sleep(int enum_rumpclock, int64_t sec, long nsec)
{
enum rumpclock clk = enum_rumpclock;
struct timespec rqt;
struct timespec ctime, delta;
unsigned long timo;
rqt.tv_sec = sec;
rqt.tv_nsec = nsec;
switch (clk) {
case RUMPUSER_CLOCK_RELWALL:
timo = timespec_to_jiffies(&rqt);
break;
case RUMPUSER_CLOCK_ABSMONO:
ctime = current_kernel_time();
delta = timespec_sub(rqt, ctime);
if (!timespec_valid(&delta))
goto out;
timo = timespec_to_jiffies(&delta);
break;
default:
panic("unreachable");
}
set_current_state(TASK_UNINTERRUPTIBLE);
KLOCK_WRAP(schedule_timeout(timo));
out:
return 0;
}
int
rumpuser_getrandom(void *buf, size_t buflen, int flags, size_t *retval)
{
/* XXX: flags not handled */
get_random_bytes(buf, buflen);
*retval = buflen;
return 0;
}