xref: /onnv-gate/usr/src/uts/i86xpv/boot/boot_xconsole.c (revision 11387:0072514d53c7)
15084Sjohnlev /*
25084Sjohnlev  * CDDL HEADER START
35084Sjohnlev  *
45084Sjohnlev  * The contents of this file are subject to the terms of the
55084Sjohnlev  * Common Development and Distribution License (the "License").
65084Sjohnlev  * You may not use this file except in compliance with the License.
75084Sjohnlev  *
85084Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95084Sjohnlev  * or http://www.opensolaris.org/os/licensing.
105084Sjohnlev  * See the License for the specific language governing permissions
115084Sjohnlev  * and limitations under the License.
125084Sjohnlev  *
135084Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
145084Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155084Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
165084Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
175084Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
185084Sjohnlev  *
195084Sjohnlev  * CDDL HEADER END
205084Sjohnlev  */
215084Sjohnlev 
225084Sjohnlev /*
23*11387SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
245084Sjohnlev  * Use is subject to license terms.
255084Sjohnlev  */
265084Sjohnlev 
275084Sjohnlev #include <sys/types.h>
285084Sjohnlev 
295084Sjohnlev #include <sys/hypervisor.h>
305084Sjohnlev #include <sys/machparam.h>
315084Sjohnlev #include <xen/public/io/console.h>
325084Sjohnlev #include <sys/mach_mmu.h>
335084Sjohnlev 
345084Sjohnlev shared_info_t *HYPERVISOR_shared_info;
355084Sjohnlev void *HYPERVISOR_console_page;
365084Sjohnlev 
375084Sjohnlev #if defined(_BOOT)
385084Sjohnlev #include "dboot/dboot_printf.h"
395084Sjohnlev char big_empty[MMU_PAGESIZE * 3];	/* room for 2 page aligned page */
405084Sjohnlev #endif /* _BOOT */
415084Sjohnlev 
425084Sjohnlev unsigned short video_fb_buf[32 * 1024 + MMU_PAGESIZE];
435084Sjohnlev unsigned char kb_status_buf[MMU_PAGESIZE * 2];
445084Sjohnlev unsigned short *video_fb = NULL;
455084Sjohnlev unsigned char *kb_status = NULL;
465084Sjohnlev 
475084Sjohnlev static volatile struct xencons_interface *cons_ifp;
485084Sjohnlev 
495084Sjohnlev #define	XR_FULL(r)	((r)->xr_in_cnt - (r)->xr_out_cnt == XR_SIZE)
505084Sjohnlev #define	XR_EMPTY(r)	((r)->xr_in_cnt == (r)->xr_out_cnt)
515084Sjohnlev 
525084Sjohnlev #define	PTE_BITS	(PT_VALID | PT_WRITABLE)
535084Sjohnlev #define	PTE_DEV_BITS	(PT_VALID | PT_WRITABLE | PT_NOCACHE | PT_NOCONSIST | \
545084Sjohnlev 			PT_FOREIGN)
555084Sjohnlev 
565084Sjohnlev /*
575084Sjohnlev  * For some unfortunate reason, the hypervisor doesn't bother to include the
585084Sjohnlev  * shared info in the original virtual address space.  This means we can't
595084Sjohnlev  * do any console I/O until we have manipulated some pagetables. So we have to
605084Sjohnlev  * do this bit of code with no ability to get debug output.
615084Sjohnlev  */
625084Sjohnlev /*ARGSUSED*/
635084Sjohnlev void
bcons_init_xen(char * cmdline)645084Sjohnlev bcons_init_xen(char *cmdline)
655084Sjohnlev {
665084Sjohnlev #ifdef _BOOT
675084Sjohnlev 	int i = 0;
685084Sjohnlev 	uintptr_t vaddr;
695084Sjohnlev 
705084Sjohnlev 	/*
715084Sjohnlev 	 * find a page aligned virtual address in "big_empty"
725084Sjohnlev 	 */
735084Sjohnlev 	vaddr = (uintptr_t)&big_empty;
745084Sjohnlev 	vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK;
755084Sjohnlev 	HYPERVISOR_shared_info = (shared_info_t *)vaddr;
765084Sjohnlev 
775084Sjohnlev 	/*
785084Sjohnlev 	 * Sets the "present" and "writable" bits in the PTE
795084Sjohnlev 	 * plus user for amd64.
805084Sjohnlev 	 */
81*11387SSurya.Prakki@Sun.COM 	(void) HYPERVISOR_update_va_mapping(vaddr,
82*11387SSurya.Prakki@Sun.COM 	    xen_info->shared_info | PTE_BITS, UVMF_INVLPG | UVMF_LOCAL);
835084Sjohnlev 
845084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
855084Sjohnlev 		/*
865084Sjohnlev 		 * map the xen console ring buffers
875084Sjohnlev 		 */
88*11387SSurya.Prakki@Sun.COM 		(void) HYPERVISOR_update_va_mapping(vaddr + MMU_PAGESIZE,
895084Sjohnlev 		    mmu_ptob((x86pte_t)xen_info->console.domU.mfn) | PTE_BITS,
905084Sjohnlev 		    UVMF_INVLPG | UVMF_LOCAL);
915084Sjohnlev 	} else {
925084Sjohnlev 		/*
935084Sjohnlev 		 * Xen will pass dom0 information about the current
945084Sjohnlev 		 * display settings via xen_info->console.dom0.  This
955084Sjohnlev 		 * information includes what video mode we're in (vga
965084Sjohnlev 		 * or vesa) and some basic information about the video
975084Sjohnlev 		 * mode.  (screen size, cursor location, etc.)  We're
985084Sjohnlev 		 * just going to ignore all this info.  Here's some
995084Sjohnlev 		 * reasons why:
1005084Sjohnlev 		 *
1015084Sjohnlev 		 * - Currently Solaris itself has no support for vesa.
1025084Sjohnlev 		 *   Also, the only way to boot Solaris is using our
1035084Sjohnlev 		 *   patched version of grub, which conveniently doesn't
1045084Sjohnlev 		 *   support vesa either.
1055084Sjohnlev 		 *
1065084Sjohnlev 		 * - By default when solaris boots up it clears the screen
1075084Sjohnlev 		 *   thereby removing any previously displayed grub/xen
1085084Sjohnlev 		 *   console messages, so we really don't care about the
1095084Sjohnlev 		 *   current vga settings.
1105084Sjohnlev 		 *
1115084Sjohnlev 		 * Initially we'll map device memory for the frame buffer
1125084Sjohnlev 		 * and keyboard into some local memory that already has
1135084Sjohnlev 		 * page table entries so that we can get very basic debug
1145084Sjohnlev 		 * output.  Later on when we're initializing page tables
1155084Sjohnlev 		 * we'll map re-map these devices to be at their expected
1165084Sjohnlev 		 * addresses.  Note that these mappings created below will
1175084Sjohnlev 		 * be torn down right before the kernel boots up when
1185084Sjohnlev 		 * all the memory and mappings associated with dboot are
1195084Sjohnlev 		 * released.
1205084Sjohnlev 		 *
1215084Sjohnlev 		 * Map the frame buffer.
1225084Sjohnlev 		 */
1235084Sjohnlev 		vaddr = (uintptr_t)&video_fb_buf;
1245084Sjohnlev 		vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK;
1255084Sjohnlev 		for (i = 0; i < 32 * 1024; i += MMU_PAGESIZE)
1265084Sjohnlev 			(void) HYPERVISOR_update_va_mapping(vaddr + i,
1275084Sjohnlev 			    0xb8000 + i | PTE_DEV_BITS,
1285084Sjohnlev 			    UVMF_INVLPG | UVMF_LOCAL);
1295084Sjohnlev 		video_fb = (unsigned short *)vaddr;
1305084Sjohnlev 
1315084Sjohnlev 		/* Map the keyboard */
1325084Sjohnlev 		vaddr = (uintptr_t)&kb_status_buf;
1335084Sjohnlev 		vaddr = (vaddr + MMU_PAGEOFFSET) & MMU_PAGEMASK;
1345084Sjohnlev 		(void) HYPERVISOR_update_va_mapping(vaddr, 0x0 | PTE_DEV_BITS,
1355084Sjohnlev 		    UVMF_INVLPG | UVMF_LOCAL);
1365084Sjohnlev 		kb_status = (unsigned char *)vaddr;
1375084Sjohnlev 	}
1385084Sjohnlev 
1395084Sjohnlev #endif /* _BOOT */
1405084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
1415084Sjohnlev 		HYPERVISOR_console_page =
1425084Sjohnlev 		    (void *)((uintptr_t)HYPERVISOR_shared_info + MMU_PAGESIZE);
1435084Sjohnlev 	} else {
1445084Sjohnlev 		HYPERVISOR_console_page = NULL;
1455084Sjohnlev 	}
1465084Sjohnlev }
1475084Sjohnlev 
1485084Sjohnlev 
1495084Sjohnlev /*
1505084Sjohnlev  * This is the equivalent of polled I/O across the hypervisor CONSOLE
1515084Sjohnlev  * channel to output 1 character at a time.
1525084Sjohnlev  */
1535084Sjohnlev void
bcons_putchar_xen(int c)1545084Sjohnlev bcons_putchar_xen(int c)
1555084Sjohnlev {
1565084Sjohnlev 	evtchn_send_t send;
1575084Sjohnlev 	char buffer = (char)c;
1585084Sjohnlev 
1595084Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
1605084Sjohnlev 		(void) HYPERVISOR_console_io(CONSOLEIO_write, 1, &buffer);
1615084Sjohnlev 		return;
1625084Sjohnlev 	}
1635084Sjohnlev 
1645084Sjohnlev 	cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page;
1655084Sjohnlev 
1665084Sjohnlev 	/*
1675084Sjohnlev 	 * need to add carriage return for new lines
1685084Sjohnlev 	 */
1695084Sjohnlev 	if (c == '\n')
1705084Sjohnlev 		bcons_putchar_xen('\r');
1715084Sjohnlev 
1725084Sjohnlev 	/*
1735084Sjohnlev 	 * We have to wait till we have an open transmit slot.
1745084Sjohnlev 	 */
1755084Sjohnlev 	while (cons_ifp->out_prod - cons_ifp->out_cons >=
1765084Sjohnlev 	    sizeof (cons_ifp->out))
1775084Sjohnlev 		(void) HYPERVISOR_yield();
1785084Sjohnlev 
1795084Sjohnlev 	cons_ifp->out[MASK_XENCONS_IDX(cons_ifp->out_prod, cons_ifp->out)] =
1805084Sjohnlev 	    (char)c;
1815084Sjohnlev 	++cons_ifp->out_prod;
1825084Sjohnlev 
1835084Sjohnlev 	/*
1845084Sjohnlev 	 * Signal Domain 0 that it has something to do for us.
1855084Sjohnlev 	 */
1865084Sjohnlev 	send.port = xen_info->console.domU.evtchn;
1875084Sjohnlev 	(void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
1885084Sjohnlev }
1895084Sjohnlev 
1905084Sjohnlev static uint_t have_char = 0;
1915084Sjohnlev static char buffered;
1925084Sjohnlev 
1935084Sjohnlev /*
1945084Sjohnlev  * See if there is a character on input.
1955084Sjohnlev  */
1965084Sjohnlev int
bcons_ischar_xen(void)1975084Sjohnlev bcons_ischar_xen(void)
1985084Sjohnlev {
1995084Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
2005084Sjohnlev 		if (have_char)
2015084Sjohnlev 			return (1);
2025084Sjohnlev 		if (HYPERVISOR_console_io(CONSOLEIO_read, 1, &buffered) > 0)
2035084Sjohnlev 			return (have_char = 1);
2045084Sjohnlev 		return (0);
2055084Sjohnlev 	}
2065084Sjohnlev 
2075084Sjohnlev 	cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page;
2085084Sjohnlev 	if (cons_ifp->in_cons == cons_ifp->in_prod)
2095084Sjohnlev 		return (0);
2105084Sjohnlev 	return (1);
2115084Sjohnlev }
2125084Sjohnlev 
2135084Sjohnlev /*
2145084Sjohnlev  * get a console input character
2155084Sjohnlev  */
2165084Sjohnlev int
bcons_getchar_xen(void)2175084Sjohnlev bcons_getchar_xen(void)
2185084Sjohnlev {
2195084Sjohnlev 	evtchn_send_t send;
2205084Sjohnlev 	char c;
2215084Sjohnlev 
2225084Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
2235084Sjohnlev 		while (have_char == 0)
2245084Sjohnlev 			(void) bcons_ischar_xen();
2255084Sjohnlev 		have_char = 0;
2265084Sjohnlev 		return (buffered);
2275084Sjohnlev 	}
2285084Sjohnlev 
2295084Sjohnlev 	cons_ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page;
2305084Sjohnlev 	while (cons_ifp->in_cons == cons_ifp->in_prod)
2315084Sjohnlev 		(void) HYPERVISOR_yield();
2325084Sjohnlev 
2335084Sjohnlev 	c = cons_ifp->in[MASK_XENCONS_IDX(cons_ifp->in_cons, cons_ifp->in)];
2345084Sjohnlev 	++cons_ifp->in_cons;
2355084Sjohnlev 
2365084Sjohnlev 	/*
2375084Sjohnlev 	 * Signal Domain 0 that we ate a character.
2385084Sjohnlev 	 */
2395084Sjohnlev 	send.port = xen_info->console.domU.evtchn;
2405084Sjohnlev 	(void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
2415084Sjohnlev 	return (c);
2425084Sjohnlev }
243