1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28
29 #include <sys/hypervisor.h>
30 #include <sys/machparam.h>
31 #include <xen/public/io/console.h>
32 #include <sys/mach_mmu.h>
33
34 shared_info_t *HYPERVISOR_shared_info;
35 void *HYPERVISOR_console_page;
36
37 #if defined(_BOOT)
38 #include "dboot/dboot_printf.h"
39 char big_empty[MMU_PAGESIZE * 3]; /* room for 2 page aligned page */
40 #endif /* _BOOT */
41
42 unsigned short video_fb_buf[32 * 1024 + MMU_PAGESIZE];
43 unsigned char kb_status_buf[MMU_PAGESIZE * 2];
44 unsigned short *video_fb = NULL;
45 unsigned char *kb_status = NULL;
46
47 static volatile struct xencons_interface *cons_ifp;
48
49 #define XR_FULL(r) ((r)->xr_in_cnt - (r)->xr_out_cnt == XR_SIZE)
50 #define XR_EMPTY(r) ((r)->xr_in_cnt == (r)->xr_out_cnt)
51
52 #define PTE_BITS (PT_VALID | PT_WRITABLE)
53 #define PTE_DEV_BITS (PT_VALID | PT_WRITABLE | PT_NOCACHE | PT_NOCONSIST | \
54 PT_FOREIGN)
55
56 /*
57 * For some unfortunate reason, the hypervisor doesn't bother to include the
58 * shared info in the original virtual address space. This means we can't
59 * do any console I/O until we have manipulated some pagetables. So we have to
60 * do this bit of code with no ability to get debug output.
61 */
62 /*ARGSUSED*/
63 void
bcons_init_xen(char * cmdline)64 bcons_init_xen(char *cmdline)
65 {
66 #ifdef _BOOT
67 int i = 0;
68 uintptr_t vaddr;
69
70 /*
71 * find a page aligned virtual address in "big_empty"
72 */
73 vaddr = (uintptr_t)&big_empty;
74 vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK;
75 HYPERVISOR_shared_info = (shared_info_t *)vaddr;
76
77 /*
78 * Sets the "present" and "writable" bits in the PTE
79 * plus user for amd64.
80 */
81 (void) HYPERVISOR_update_va_mapping(vaddr,
82 xen_info->shared_info | PTE_BITS, UVMF_INVLPG | UVMF_LOCAL);
83
84 if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
85 /*
86 * map the xen console ring buffers
87 */
88 (void) HYPERVISOR_update_va_mapping(vaddr + MMU_PAGESIZE,
89 mmu_ptob((x86pte_t)xen_info->console.domU.mfn) | PTE_BITS,
90 UVMF_INVLPG | UVMF_LOCAL);
91 } else {
92 /*
93 * Xen will pass dom0 information about the current
94 * display settings via xen_info->console.dom0. This
95 * information includes what video mode we're in (vga
96 * or vesa) and some basic information about the video
97 * mode. (screen size, cursor location, etc.) We're
98 * just going to ignore all this info. Here's some
99 * reasons why:
100 *
101 * - Currently Solaris itself has no support for vesa.
102 * Also, the only way to boot Solaris is using our
103 * patched version of grub, which conveniently doesn't
104 * support vesa either.
105 *
106 * - By default when solaris boots up it clears the screen
107 * thereby removing any previously displayed grub/xen
108 * console messages, so we really don't care about the
109 * current vga settings.
110 *
111 * Initially we'll map device memory for the frame buffer
112 * and keyboard into some local memory that already has
113 * page table entries so that we can get very basic debug
114 * output. Later on when we're initializing page tables
115 * we'll map re-map these devices to be at their expected
116 * addresses. Note that these mappings created below will
117 * be torn down right before the kernel boots up when
118 * all the memory and mappings associated with dboot are
119 * released.
120 *
121 * Map the frame buffer.
122 */
123 vaddr = (uintptr_t)&video_fb_buf;
124 vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK;
125 for (i = 0; i < 32 * 1024; i += MMU_PAGESIZE)
126 (void) HYPERVISOR_update_va_mapping(vaddr + i,
127 0xb8000 + i | PTE_DEV_BITS,
128 UVMF_INVLPG | UVMF_LOCAL);
129 video_fb = (unsigned short *)vaddr;
130
131 /* Map the keyboard */
132 vaddr = (uintptr_t)&kb_status_buf;
133 vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK;
134 (void) HYPERVISOR_update_va_mapping(vaddr, 0x0 | PTE_DEV_BITS,
135 UVMF_INVLPG | UVMF_LOCAL);
136 kb_status = (unsigned char *)vaddr;
137 }
138
139 #endif /* _BOOT */
140 if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
141 HYPERVISOR_console_page =
142 (void *)((uintptr_t)HYPERVISOR_shared_info + MMU_PAGESIZE);
143 } else {
144 HYPERVISOR_console_page = NULL;
145 }
146 }
147
148
149 /*
150 * This is the equivalent of polled I/O across the hypervisor CONSOLE
151 * channel to output 1 character at a time.
152 */
153 void
bcons_putchar_xen(int c)154 bcons_putchar_xen(int c)
155 {
156 evtchn_send_t send;
157 char buffer = (char)c;
158
159 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
160 (void) HYPERVISOR_console_io(CONSOLEIO_write, 1, &buffer);
161 return;
162 }
163
164 cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page;
165
166 /*
167 * need to add carriage return for new lines
168 */
169 if (c == '\n')
170 bcons_putchar_xen('\r');
171
172 /*
173 * We have to wait till we have an open transmit slot.
174 */
175 while (cons_ifp->out_prod - cons_ifp->out_cons >=
176 sizeof (cons_ifp->out))
177 (void) HYPERVISOR_yield();
178
179 cons_ifp->out[MASK_XENCONS_IDX(cons_ifp->out_prod, cons_ifp->out)] =
180 (char)c;
181 ++cons_ifp->out_prod;
182
183 /*
184 * Signal Domain 0 that it has something to do for us.
185 */
186 send.port = xen_info->console.domU.evtchn;
187 (void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
188 }
189
190 static uint_t have_char = 0;
191 static char buffered;
192
193 /*
194 * See if there is a character on input.
195 */
196 int
bcons_ischar_xen(void)197 bcons_ischar_xen(void)
198 {
199 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
200 if (have_char)
201 return (1);
202 if (HYPERVISOR_console_io(CONSOLEIO_read, 1, &buffered) > 0)
203 return (have_char = 1);
204 return (0);
205 }
206
207 cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page;
208 if (cons_ifp->in_cons == cons_ifp->in_prod)
209 return (0);
210 return (1);
211 }
212
213 /*
214 * get a console input character
215 */
216 int
bcons_getchar_xen(void)217 bcons_getchar_xen(void)
218 {
219 evtchn_send_t send;
220 char c;
221
222 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
223 while (have_char == 0)
224 (void) bcons_ischar_xen();
225 have_char = 0;
226 return (buffered);
227 }
228
229 cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page;
230 while (cons_ifp->in_cons == cons_ifp->in_prod)
231 (void) HYPERVISOR_yield();
232
233 c = cons_ifp->in[MASK_XENCONS_IDX(cons_ifp->in_cons, cons_ifp->in)];
234 ++cons_ifp->in_cons;
235
236 /*
237 * Signal Domain 0 that we ate a character.
238 */
239 send.port = xen_info->console.domU.evtchn;
240 (void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
241 return (c);
242 }
243