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