xref: /kvmtool/powerpc/spapr_rtas.c (revision 2aa76b2616bcace1d668a879d834679dfa00dc8c)
1 /*
2  * SPAPR base RTAS calls
3  *
4  * Borrowed heavily from QEMU's spapr_rtas.c
5  * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
6  *
7  * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License version 2 as published
11  * by the Free Software Foundation.
12  */
13 
14 #include "kvm/kvm.h"
15 #include "kvm/kvm-cpu.h"
16 #include "kvm/util.h"
17 #include "kvm/term.h"
18 
19 #include "spapr.h"
20 
21 #include <libfdt.h>
22 #include <stdio.h>
23 #include <assert.h>
24 
25 #define TOKEN_BASE      0x2000
26 #define TOKEN_MAX       0x100
27 
28 #define RTAS_CONSOLE
29 
30 static struct rtas_call {
31 	const char *name;
32 	spapr_rtas_fn fn;
33 } rtas_table[TOKEN_MAX];
34 
35 struct rtas_call *rtas_next = rtas_table;
36 
37 
rtas_display_character(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)38 static void rtas_display_character(struct kvm_cpu *vcpu,
39                                    uint32_t token, uint32_t nargs,
40                                    target_ulong args,
41                                    uint32_t nret, target_ulong rets)
42 {
43 	char c = rtas_ld(vcpu->kvm, args, 0);
44 	term_putc(&c, 1, 0);
45 	rtas_st(vcpu->kvm, rets, 0, 0);
46 }
47 
48 #ifdef RTAS_CONSOLE
rtas_put_term_char(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)49 static void rtas_put_term_char(struct kvm_cpu *vcpu,
50 			       uint32_t token, uint32_t nargs,
51 			       target_ulong args,
52 			       uint32_t nret, target_ulong rets)
53 {
54 	char c = rtas_ld(vcpu->kvm, args, 0);
55 
56 	term_putc(&c, 1, 0);
57 
58 	rtas_st(vcpu->kvm, rets, 0, 0);
59 }
60 
rtas_get_term_char(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)61 static void rtas_get_term_char(struct kvm_cpu *vcpu,
62 			       uint32_t token, uint32_t nargs,
63 			       target_ulong args,
64 			       uint32_t nret, target_ulong rets)
65 {
66 	int c;
67 
68 	if (vcpu->kvm->cfg.active_console == CONSOLE_HV && term_readable(0) &&
69 	    (c = term_getc(vcpu->kvm, 0)) >= 0) {
70 		rtas_st(vcpu->kvm, rets, 0, 0);
71 		rtas_st(vcpu->kvm, rets, 1, c);
72 	} else {
73 		rtas_st(vcpu->kvm, rets, 0, -2);
74 	}
75 }
76 #endif
77 
rtas_get_time_of_day(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)78 static void rtas_get_time_of_day(struct kvm_cpu *vcpu,
79                                  uint32_t token, uint32_t nargs,
80                                  target_ulong args,
81                                  uint32_t nret, target_ulong rets)
82 {
83 	struct tm tm;
84 	time_t tnow;
85 
86 	if (nret != 8) {
87 		rtas_st(vcpu->kvm, rets, 0, -3);
88 		return;
89 	}
90 
91 	tnow = time(NULL);
92 	/* Guest time is currently not offset in any way. */
93 	gmtime_r(&tnow, &tm);
94 
95 	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
96 	rtas_st(vcpu->kvm, rets, 1, tm.tm_year + 1900);
97 	rtas_st(vcpu->kvm, rets, 2, tm.tm_mon + 1);
98 	rtas_st(vcpu->kvm, rets, 3, tm.tm_mday);
99 	rtas_st(vcpu->kvm, rets, 4, tm.tm_hour);
100 	rtas_st(vcpu->kvm, rets, 5, tm.tm_min);
101 	rtas_st(vcpu->kvm, rets, 6, tm.tm_sec);
102 	rtas_st(vcpu->kvm, rets, 7, 0);
103 }
104 
rtas_set_time_of_day(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)105 static void rtas_set_time_of_day(struct kvm_cpu *vcpu,
106                                  uint32_t token, uint32_t nargs,
107                                  target_ulong args,
108                                  uint32_t nret, target_ulong rets)
109 {
110 	pr_warning("%s called; TOD set ignored.\n", __FUNCTION__);
111 }
112 
rtas_power_off(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)113 static void rtas_power_off(struct kvm_cpu *vcpu,
114                            uint32_t token, uint32_t nargs, target_ulong args,
115                            uint32_t nret, target_ulong rets)
116 {
117 	if (nargs != 2 || nret != 1) {
118 		rtas_st(vcpu->kvm, rets, 0, -3);
119 		return;
120 	}
121 	kvm__reboot(vcpu->kvm);
122 }
123 
rtas_system_reboot(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)124 static void rtas_system_reboot(struct kvm_cpu *vcpu,
125                            uint32_t token, uint32_t nargs, target_ulong args,
126                            uint32_t nret, target_ulong rets)
127 {
128 	if (nargs != 0 || nret != 1) {
129 		rtas_st(vcpu->kvm, rets, 0, -3);
130 		return;
131 	}
132 
133 	/* NB this actually halts the VM */
134 	kvm__reboot(vcpu->kvm);
135 }
136 
rtas_query_cpu_stopped_state(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)137 static void rtas_query_cpu_stopped_state(struct kvm_cpu *vcpu,
138                                          uint32_t token, uint32_t nargs,
139                                          target_ulong args,
140                                          uint32_t nret, target_ulong rets)
141 {
142 	if (nargs != 1 || nret != 2) {
143 		rtas_st(vcpu->kvm, rets, 0, -3);
144 		return;
145 	}
146 
147 	/*
148 	 * Can read id = rtas_ld(vcpu->kvm, args, 0), but
149 	 * we currently start all CPUs.  So just return true.
150 	 */
151 	rtas_st(vcpu->kvm, rets, 0, 0);
152 	rtas_st(vcpu->kvm, rets, 1, 2);
153 }
154 
rtas_start_cpu(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)155 static void rtas_start_cpu(struct kvm_cpu *vcpu,
156                            uint32_t token, uint32_t nargs,
157                            target_ulong args,
158                            uint32_t nret, target_ulong rets)
159 {
160 	die(__FUNCTION__);
161 }
162 
spapr_rtas_call(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)163 target_ulong spapr_rtas_call(struct kvm_cpu *vcpu,
164                              uint32_t token, uint32_t nargs, target_ulong args,
165                              uint32_t nret, target_ulong rets)
166 {
167 	if ((token >= TOKEN_BASE)
168 	    && ((token - TOKEN_BASE) < TOKEN_MAX)) {
169 		struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
170 
171 		if (call->fn) {
172 			call->fn(vcpu, token, nargs, args, nret, rets);
173 			return H_SUCCESS;
174 		}
175 	}
176 
177 	/*
178 	 * HACK: Some Linux early debug code uses RTAS display-character,
179 	 * but assumes the token value is 0xa (which it is on some real
180 	 * machines) without looking it up in the device tree.  This
181 	 * special case makes this work
182 	 */
183 	if (token == 0xa) {
184 		rtas_display_character(vcpu, 0xa, nargs, args, nret, rets);
185 		return H_SUCCESS;
186 	}
187 
188 	hcall_dprintf("Unknown RTAS token 0x%x\n", token);
189 	rtas_st(vcpu->kvm, rets, 0, -3);
190 	return H_PARAMETER;
191 }
192 
spapr_rtas_register(const char * name,spapr_rtas_fn fn)193 void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
194 {
195 	assert(rtas_next < (rtas_table + TOKEN_MAX));
196 
197 	rtas_next->name = name;
198 	rtas_next->fn = fn;
199 
200 	rtas_next++;
201 }
202 
203 /*
204  * This is called from the context of an open /rtas node, in order to add
205  * properties for the rtas call tokens.
206  */
spapr_rtas_fdt_setup(struct kvm * kvm,void * fdt)207 int spapr_rtas_fdt_setup(struct kvm *kvm, void *fdt)
208 {
209 	int ret;
210 	int i;
211 
212 	for (i = 0; i < TOKEN_MAX; i++) {
213 		struct rtas_call *call = &rtas_table[i];
214 
215 		if (!call->fn) {
216 			continue;
217 		}
218 
219 		ret = fdt_property_cell(fdt, call->name, i + TOKEN_BASE);
220 
221 		if (ret < 0) {
222 			pr_warning("Couldn't add rtas token for %s: %s\n",
223 				   call->name, fdt_strerror(ret));
224 			return ret;
225 		}
226 
227 	}
228 	return 0;
229 }
230 
register_core_rtas(void)231 void register_core_rtas(void)
232 {
233 	spapr_rtas_register("display-character", rtas_display_character);
234 	spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
235 	spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
236 	spapr_rtas_register("power-off", rtas_power_off);
237 	spapr_rtas_register("system-reboot", rtas_system_reboot);
238 	spapr_rtas_register("query-cpu-stopped-state",
239 			    rtas_query_cpu_stopped_state);
240 	spapr_rtas_register("start-cpu", rtas_start_cpu);
241 #ifdef RTAS_CONSOLE
242 	/* These are unused: We do console I/O via hcalls, not rtas. */
243 	spapr_rtas_register("put-term-char", rtas_put_term_char);
244 	spapr_rtas_register("get-term-char", rtas_get_term_char);
245 #endif
246 }
247