]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/xen/uartxen.c
bcm: flush out early boot messages on uart and screen initialization
[plan9front.git] / sys / src / 9 / xen / uartxen.c
1 /*
2  * xencons.c
3  *      Access to xen consoles.
4  */
5
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "../port/error.h"
12 #include "../pc/io.h"
13
14 extern PhysUart xenphysuart;
15
16 static Uart xenuart = {
17         .name = "xencons",
18         .freq = 1843200,
19         .phys = &xenphysuart,
20 };
21
22 struct {
23         struct xencons_interface *intf;
24         int evtchn;
25         Lock txlock;
26 } xencons;
27
28 /*
29  * Debug print to xen "emergency console".
30  * Output only appears if xen is built with verbose=y
31  */
32 void
33 dprint(char *fmt, ...)
34 {
35         int n;
36         va_list arg;
37         char buf[PRINTSIZE];
38
39         va_start(arg, fmt);
40         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
41         va_end(arg);
42         HYPERVISOR_console_io(CONSOLEIO_write, n, buf);
43 }
44
45 static void kick(Uart*);
46 /*
47  * Emit a string to the guest OS console, bypassing the queue
48  *   - before serialoq is initialised
49  *   - when rdb is activated
50  *   - from iprint() for messages from interrupt routines
51  * If ring is full, just throw extra output away.
52  */
53 void
54 xenuartputs(char *s, int n)
55 {
56         struct xencons_interface *con = xencons.intf;
57         unsigned long prod;
58         int c;
59
60         ilock(&xencons.txlock);
61         prod = con->out_prod;
62         while (n-- > 0 && (prod - con->out_cons) < sizeof(con->out)) {
63                 c = *s++;
64                 /*
65                 if (c == '\n')
66                         con->out[MASK_XENCONS_IDX(prod++, con->out)] = '\r';
67                 */
68                 con->out[MASK_XENCONS_IDX(prod++, con->out)] = c;
69         }
70         coherence();
71         con->out_prod = prod;
72         xenchannotify(xencons.evtchn);
73         iunlock(&xencons.txlock);
74 }
75
76 /*
77  * Handle channel event from console
78  */
79 static void
80 interrupt(Ureg*, void *arg)
81 {
82         char c;
83         unsigned long cons;
84         Uart *uart;
85         struct xencons_interface *con = xencons.intf;
86
87         uart = &xenuart;
88
89         cons = con->in_cons;
90         coherence();
91         while (cons != con->in_prod) {
92                 c = con->in[MASK_XENCONS_IDX(cons++, con->in)];
93                 uartrecv(uart, c);
94         }
95         coherence();
96         con->in_cons = cons;
97         kick(nil);
98 }
99
100 static Uart*
101 pnp(void)
102 {
103         return &xenuart;
104 }
105
106 static void
107 enable(Uart*, int ie)
108 {
109         if(ie)
110                 intrenable(xencons.evtchn, interrupt, 0, BUSUNKNOWN, "Xen console");
111 }
112
113 static void
114 disable(Uart*)
115 {
116 }
117
118 /*
119  * Send queued output to guest OS console
120  */
121 static void
122 kick(Uart*)
123 {
124         struct xencons_interface *con = xencons.intf;
125         unsigned long prod;
126         long avail, idx, n, m;
127
128         ilock(&xencons.txlock);
129         prod = con->out_prod;
130         avail = sizeof(con->out) - (prod - con->out_cons);
131         while (avail > 0) {
132                 idx = MASK_XENCONS_IDX(prod, con->out);
133                 m = sizeof(con->out) - idx;
134                 if (m > avail)
135                         m = avail;
136                 n = qconsume(serialoq, con->out+idx, m);
137                 if (n < 0)
138                         break;
139                 prod += n;
140                 avail -= n;
141         }
142         coherence();
143         con->out_prod = prod;
144         xenchannotify(xencons.evtchn);
145         iunlock(&xencons.txlock);
146 }
147
148 static void
149 donothing(Uart*, int)
150 {
151 }
152
153 static int
154 donothingint(Uart*, int)
155 {
156         return 0;
157 }
158
159 static int
160 baud(Uart *uart, int n)
161 {
162         if(n <= 0)
163                 return -1;
164
165         uart->baud = n;
166         return 0;
167 }
168
169 static int
170 bits(Uart *uart, int n)
171 {
172         switch(n){
173         case 7:
174         case 8:
175                 break;
176         default:
177                 return -1;
178         }
179
180         uart->bits = n;
181         return 0;
182 }
183
184 static int
185 stop(Uart *uart, int n)
186 {
187         if(n != 1)
188                 return -1;
189         uart->stop = n;
190         return 0;
191 }
192
193 static int
194 parity(Uart *uart, int n)
195 {
196         if(n != 'n')
197                 return -1;
198         uart->parity = n;
199         return 0;
200 }
201
202 static long
203 status(Uart *uart, void *buf, long n, long offset)
204 {
205         char *p;
206
207         p = malloc(READSTR);
208         if(p == nil)
209                 error(Enomem);
210         snprint(p, READSTR,
211                 "b%d\n"
212                 "dev(%d) type(%d) framing(%d) overruns(%d) "
213                 "berr(%d) serr(%d)\n",
214
215                 uart->baud,
216                 uart->dev,
217                 uart->type,
218                 uart->ferr,
219                 uart->oerr,
220                 uart->berr,
221                 uart->serr
222         );
223         n = readstr(offset, buf, n, p);
224         free(p);
225
226         return n;
227 }
228
229 void
230 xenputc(Uart*, int c)
231 {
232         struct xencons_interface *con = xencons.intf;
233         unsigned long prod;
234
235         ilock(&xencons.txlock);
236         prod = con->out_prod;
237         if((prod - con->out_cons) < sizeof(con->out)){
238                 if (c == '\n')
239                         con->out[MASK_XENCONS_IDX(prod++, con->out)] = '\r';
240                 con->out[MASK_XENCONS_IDX(prod++, con->out)] = c;
241         }
242
243         coherence();
244         con->out_prod = prod;
245         xenchannotify(xencons.evtchn);
246         iunlock(&xencons.txlock);
247 }
248
249 int
250 xengetc(Uart*)
251 {
252         struct xencons_interface *con = xencons.intf;
253         char c;
254
255         c = 0;
256
257         if(con->in_cons != con->in_prod){
258                 coherence();
259                 c = con->in[MASK_XENCONS_IDX(con->in_cons++, con->in)];
260                 if (con->in_cons == con->in_prod)
261                         xenchannotify(xencons.evtchn);
262         }
263
264         return c;
265 }
266
267 PhysUart xenphysuart = {
268         .name           = "xenuart",
269
270         .pnp            = pnp,
271         .enable         = enable,
272         .disable        = disable,
273         .kick           = kick,
274         .dobreak        = donothing,
275         .baud           = baud,
276         .bits           = bits,
277         .stop           = stop,
278         .parity         = parity,
279         .modemctl       = donothing,
280         .rts            = donothing,
281         .dtr            = donothing,
282         .status         = status,
283         .fifo           = donothing,
284
285         .getc           = xengetc,
286         .putc           = xenputc,
287 };
288
289 /* console=0 to enable */
290 void
291 xenconsinit(void)
292 {
293         xencons.intf = (struct xencons_interface*)mmumapframe(XENCONSOLE, xenstart->console_mfn);
294         xencons.evtchn = xenstart->console_evtchn;
295
296         consuart = &xenuart;
297         consuart->console = 1;
298 }
299
300 void
301 kbdenable(void)
302 {
303         Uart *uart;
304         int n;
305         char *p, *cmd;
306
307         if((p = getconf("console")) == nil)
308                 return;
309         n = strtoul(p, &cmd, 0);
310         if(p == cmd || n != 0)
311                 return;
312         uart = &xenuart;
313
314         (*uart->phys->enable)(uart, 0);
315         uartctl(uart, "b9600 l8 pn s1");
316         if(*cmd != '\0')
317                 uartctl(uart, cmd);
318
319         consuart = uart;
320         uart->console = 1;
321 }
322