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