1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev 22843e1988Sjohnlev /* 23*c1374a13SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24843e1988Sjohnlev * Use is subject to license terms. 25843e1988Sjohnlev */ 26843e1988Sjohnlev 27843e1988Sjohnlev #include <sys/types.h> 28843e1988Sjohnlev 29843e1988Sjohnlev #include <sys/hypervisor.h> 30843e1988Sjohnlev #include <sys/machparam.h> 31843e1988Sjohnlev #include <xen/public/io/console.h> 32843e1988Sjohnlev #include <sys/mach_mmu.h> 33843e1988Sjohnlev 34843e1988Sjohnlev shared_info_t *HYPERVISOR_shared_info; 35843e1988Sjohnlev void *HYPERVISOR_console_page; 36843e1988Sjohnlev 37843e1988Sjohnlev #if defined(_BOOT) 38843e1988Sjohnlev #include "dboot/dboot_printf.h" 39843e1988Sjohnlev char big_empty[MMU_PAGESIZE * 3]; /* room for 2 page aligned page */ 40843e1988Sjohnlev #endif /* _BOOT */ 41843e1988Sjohnlev 42843e1988Sjohnlev unsigned short video_fb_buf[32 * 1024 + MMU_PAGESIZE]; 43843e1988Sjohnlev unsigned char kb_status_buf[MMU_PAGESIZE * 2]; 44843e1988Sjohnlev unsigned short *video_fb = NULL; 45843e1988Sjohnlev unsigned char *kb_status = NULL; 46843e1988Sjohnlev 47843e1988Sjohnlev static volatile struct xencons_interface *cons_ifp; 48843e1988Sjohnlev 49843e1988Sjohnlev #define XR_FULL(r) ((r)->xr_in_cnt - (r)->xr_out_cnt == XR_SIZE) 50843e1988Sjohnlev #define XR_EMPTY(r) ((r)->xr_in_cnt == (r)->xr_out_cnt) 51843e1988Sjohnlev 52843e1988Sjohnlev #define PTE_BITS (PT_VALID | PT_WRITABLE) 53843e1988Sjohnlev #define PTE_DEV_BITS (PT_VALID | PT_WRITABLE | PT_NOCACHE | PT_NOCONSIST | \ 54843e1988Sjohnlev PT_FOREIGN) 55843e1988Sjohnlev 56843e1988Sjohnlev /* 57843e1988Sjohnlev * For some unfortunate reason, the hypervisor doesn't bother to include the 58843e1988Sjohnlev * shared info in the original virtual address space. This means we can't 59843e1988Sjohnlev * do any console I/O until we have manipulated some pagetables. So we have to 60843e1988Sjohnlev * do this bit of code with no ability to get debug output. 61843e1988Sjohnlev */ 62843e1988Sjohnlev /*ARGSUSED*/ 63843e1988Sjohnlev void 64843e1988Sjohnlev bcons_init_xen(char *cmdline) 65843e1988Sjohnlev { 66843e1988Sjohnlev #ifdef _BOOT 67843e1988Sjohnlev int i = 0; 68843e1988Sjohnlev uintptr_t vaddr; 69843e1988Sjohnlev 70843e1988Sjohnlev /* 71843e1988Sjohnlev * find a page aligned virtual address in "big_empty" 72843e1988Sjohnlev */ 73843e1988Sjohnlev vaddr = (uintptr_t)&big_empty; 74843e1988Sjohnlev vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK; 75843e1988Sjohnlev HYPERVISOR_shared_info = (shared_info_t *)vaddr; 76843e1988Sjohnlev 77843e1988Sjohnlev /* 78843e1988Sjohnlev * Sets the "present" and "writable" bits in the PTE 79843e1988Sjohnlev * plus user for amd64. 80843e1988Sjohnlev */ 81*c1374a13SSurya Prakki (void) HYPERVISOR_update_va_mapping(vaddr, 82*c1374a13SSurya Prakki xen_info->shared_info | PTE_BITS, UVMF_INVLPG | UVMF_LOCAL); 83843e1988Sjohnlev 84843e1988Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 85843e1988Sjohnlev /* 86843e1988Sjohnlev * map the xen console ring buffers 87843e1988Sjohnlev */ 88*c1374a13SSurya Prakki (void) HYPERVISOR_update_va_mapping(vaddr + MMU_PAGESIZE, 89843e1988Sjohnlev mmu_ptob((x86pte_t)xen_info->console.domU.mfn) | PTE_BITS, 90843e1988Sjohnlev UVMF_INVLPG | UVMF_LOCAL); 91843e1988Sjohnlev } else { 92843e1988Sjohnlev /* 93843e1988Sjohnlev * Xen will pass dom0 information about the current 94843e1988Sjohnlev * display settings via xen_info->console.dom0. This 95843e1988Sjohnlev * information includes what video mode we're in (vga 96843e1988Sjohnlev * or vesa) and some basic information about the video 97843e1988Sjohnlev * mode. (screen size, cursor location, etc.) We're 98843e1988Sjohnlev * just going to ignore all this info. Here's some 99843e1988Sjohnlev * reasons why: 100843e1988Sjohnlev * 101843e1988Sjohnlev * - Currently Solaris itself has no support for vesa. 102843e1988Sjohnlev * Also, the only way to boot Solaris is using our 103843e1988Sjohnlev * patched version of grub, which conveniently doesn't 104843e1988Sjohnlev * support vesa either. 105843e1988Sjohnlev * 106843e1988Sjohnlev * - By default when solaris boots up it clears the screen 107843e1988Sjohnlev * thereby removing any previously displayed grub/xen 108843e1988Sjohnlev * console messages, so we really don't care about the 109843e1988Sjohnlev * current vga settings. 110843e1988Sjohnlev * 111843e1988Sjohnlev * Initially we'll map device memory for the frame buffer 112843e1988Sjohnlev * and keyboard into some local memory that already has 113843e1988Sjohnlev * page table entries so that we can get very basic debug 114843e1988Sjohnlev * output. Later on when we're initializing page tables 115843e1988Sjohnlev * we'll map re-map these devices to be at their expected 116843e1988Sjohnlev * addresses. Note that these mappings created below will 117843e1988Sjohnlev * be torn down right before the kernel boots up when 118843e1988Sjohnlev * all the memory and mappings associated with dboot are 119843e1988Sjohnlev * released. 120843e1988Sjohnlev * 121843e1988Sjohnlev * Map the frame buffer. 122843e1988Sjohnlev */ 123843e1988Sjohnlev vaddr = (uintptr_t)&video_fb_buf; 124843e1988Sjohnlev vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK; 125843e1988Sjohnlev for (i = 0; i < 32 * 1024; i += MMU_PAGESIZE) 126843e1988Sjohnlev (void) HYPERVISOR_update_va_mapping(vaddr + i, 127843e1988Sjohnlev 0xb8000 + i | PTE_DEV_BITS, 128843e1988Sjohnlev UVMF_INVLPG | UVMF_LOCAL); 129843e1988Sjohnlev video_fb = (unsigned short *)vaddr; 130843e1988Sjohnlev 131843e1988Sjohnlev /* Map the keyboard */ 132843e1988Sjohnlev vaddr = (uintptr_t)&kb_status_buf; 133843e1988Sjohnlev vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK; 134843e1988Sjohnlev (void) HYPERVISOR_update_va_mapping(vaddr, 0x0 | PTE_DEV_BITS, 135843e1988Sjohnlev UVMF_INVLPG | UVMF_LOCAL); 136843e1988Sjohnlev kb_status = (unsigned char *)vaddr; 137843e1988Sjohnlev } 138843e1988Sjohnlev 139843e1988Sjohnlev #endif /* _BOOT */ 140843e1988Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 141843e1988Sjohnlev HYPERVISOR_console_page = 142843e1988Sjohnlev (void *)((uintptr_t)HYPERVISOR_shared_info + MMU_PAGESIZE); 143843e1988Sjohnlev } else { 144843e1988Sjohnlev HYPERVISOR_console_page = NULL; 145843e1988Sjohnlev } 146843e1988Sjohnlev } 147843e1988Sjohnlev 148843e1988Sjohnlev 149843e1988Sjohnlev /* 150843e1988Sjohnlev * This is the equivalent of polled I/O across the hypervisor CONSOLE 151843e1988Sjohnlev * channel to output 1 character at a time. 152843e1988Sjohnlev */ 153843e1988Sjohnlev void 154843e1988Sjohnlev bcons_putchar_xen(int c) 155843e1988Sjohnlev { 156843e1988Sjohnlev evtchn_send_t send; 157843e1988Sjohnlev char buffer = (char)c; 158843e1988Sjohnlev 159843e1988Sjohnlev if (DOMAIN_IS_INITDOMAIN(xen_info)) { 160843e1988Sjohnlev (void) HYPERVISOR_console_io(CONSOLEIO_write, 1, &buffer); 161843e1988Sjohnlev return; 162843e1988Sjohnlev } 163843e1988Sjohnlev 164843e1988Sjohnlev cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page; 165843e1988Sjohnlev 166843e1988Sjohnlev /* 167843e1988Sjohnlev * need to add carriage return for new lines 168843e1988Sjohnlev */ 169843e1988Sjohnlev if (c == '\n') 170843e1988Sjohnlev bcons_putchar_xen('\r'); 171843e1988Sjohnlev 172843e1988Sjohnlev /* 173843e1988Sjohnlev * We have to wait till we have an open transmit slot. 174843e1988Sjohnlev */ 175843e1988Sjohnlev while (cons_ifp->out_prod - cons_ifp->out_cons >= 176843e1988Sjohnlev sizeof (cons_ifp->out)) 177843e1988Sjohnlev (void) HYPERVISOR_yield(); 178843e1988Sjohnlev 179843e1988Sjohnlev cons_ifp->out[MASK_XENCONS_IDX(cons_ifp->out_prod, cons_ifp->out)] = 180843e1988Sjohnlev (char)c; 181843e1988Sjohnlev ++cons_ifp->out_prod; 182843e1988Sjohnlev 183843e1988Sjohnlev /* 184843e1988Sjohnlev * Signal Domain 0 that it has something to do for us. 185843e1988Sjohnlev */ 186843e1988Sjohnlev send.port = xen_info->console.domU.evtchn; 187843e1988Sjohnlev (void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); 188843e1988Sjohnlev } 189843e1988Sjohnlev 190843e1988Sjohnlev static uint_t have_char = 0; 191843e1988Sjohnlev static char buffered; 192843e1988Sjohnlev 193843e1988Sjohnlev /* 194843e1988Sjohnlev * See if there is a character on input. 195843e1988Sjohnlev */ 196843e1988Sjohnlev int 197843e1988Sjohnlev bcons_ischar_xen(void) 198843e1988Sjohnlev { 199843e1988Sjohnlev if (DOMAIN_IS_INITDOMAIN(xen_info)) { 200843e1988Sjohnlev if (have_char) 201843e1988Sjohnlev return (1); 202843e1988Sjohnlev if (HYPERVISOR_console_io(CONSOLEIO_read, 1, &buffered) > 0) 203843e1988Sjohnlev return (have_char = 1); 204843e1988Sjohnlev return (0); 205843e1988Sjohnlev } 206843e1988Sjohnlev 207843e1988Sjohnlev cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page; 208843e1988Sjohnlev if (cons_ifp->in_cons == cons_ifp->in_prod) 209843e1988Sjohnlev return (0); 210843e1988Sjohnlev return (1); 211843e1988Sjohnlev } 212843e1988Sjohnlev 213843e1988Sjohnlev /* 214843e1988Sjohnlev * get a console input character 215843e1988Sjohnlev */ 216843e1988Sjohnlev int 217843e1988Sjohnlev bcons_getchar_xen(void) 218843e1988Sjohnlev { 219843e1988Sjohnlev evtchn_send_t send; 220843e1988Sjohnlev char c; 221843e1988Sjohnlev 222843e1988Sjohnlev if (DOMAIN_IS_INITDOMAIN(xen_info)) { 223843e1988Sjohnlev while (have_char == 0) 224843e1988Sjohnlev (void) bcons_ischar_xen(); 225843e1988Sjohnlev have_char = 0; 226843e1988Sjohnlev return (buffered); 227843e1988Sjohnlev } 228843e1988Sjohnlev 229843e1988Sjohnlev cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page; 230843e1988Sjohnlev while (cons_ifp->in_cons == cons_ifp->in_prod) 231843e1988Sjohnlev (void) HYPERVISOR_yield(); 232843e1988Sjohnlev 233843e1988Sjohnlev c = cons_ifp->in[MASK_XENCONS_IDX(cons_ifp->in_cons, cons_ifp->in)]; 234843e1988Sjohnlev ++cons_ifp->in_cons; 235843e1988Sjohnlev 236843e1988Sjohnlev /* 237843e1988Sjohnlev * Signal Domain 0 that we ate a character. 238843e1988Sjohnlev */ 239843e1988Sjohnlev send.port = xen_info->console.domU.evtchn; 240843e1988Sjohnlev (void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); 241843e1988Sjohnlev return (c); 242843e1988Sjohnlev } 243