17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21ae115bc7Smrj 227c478bd9Sstevel@tonic-gate /* 23ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Miniature VGA driver for bootstrap. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 327c478bd9Sstevel@tonic-gate #include <sys/vgareg.h> 338e6d016fSToomas Soome #include <sys/framebuffer.h> 34*29a77b73SToomas Soome #include <sys/boot_console.h> 35*29a77b73SToomas Soome #include "boot_console_impl.h" 36ae115bc7Smrj 378e6d016fSToomas Soome #include "boot_console_impl.h" 38ae115bc7Smrj #if defined(_BOOT) 39843e1988Sjohnlev #include "../dboot/dboot_asm.h" 40ae115bc7Smrj #include "../dboot/dboot_xboot.h" 41ae115bc7Smrj #endif 427c478bd9Sstevel@tonic-gate 43843e1988Sjohnlev #if defined(__xpv) && defined(_BOOT) 44843e1988Sjohnlev 45843e1988Sjohnlev /* 46843e1988Sjohnlev * Device memory address 47843e1988Sjohnlev * 48843e1988Sjohnlev * In dboot under the hypervisor we don't have any memory mappings 49843e1988Sjohnlev * for the first meg of low memory so we can't access devices there. 50843e1988Sjohnlev * Intead we've mapped the device memory that we need to access into 51843e1988Sjohnlev * a local variable within dboot so we can access the device memory 52843e1988Sjohnlev * there. 53843e1988Sjohnlev */ 54843e1988Sjohnlev extern unsigned short *video_fb; 55*29a77b73SToomas Soome #define VGA_SCREEN (video_fb) 56843e1988Sjohnlev 57843e1988Sjohnlev #else /* __xpv && _BOOT */ 58843e1988Sjohnlev 59843e1988Sjohnlev /* Device memory address */ 608e6d016fSToomas Soome #define VGA_SCREEN ((uint16_t *)(VGA_MEM_ADDR + VGA_COLOR_BASE)) 617c478bd9Sstevel@tonic-gate 62843e1988Sjohnlev #endif /* __xpv && _BOOT */ 63843e1988Sjohnlev 64*29a77b73SToomas Soome static int cons_color = CONS_COLOR; 65843e1988Sjohnlev 668e6d016fSToomas Soome static void vga_init(void); 67*29a77b73SToomas Soome static void vga_drawc(int); 68*29a77b73SToomas Soome static void vga_setpos(int, int); 69*29a77b73SToomas Soome static void vga_getpos(int *, int *); 70*29a77b73SToomas Soome static void vga_scroll(int); 718e6d016fSToomas Soome static void vga_clear(int); 72*29a77b73SToomas Soome static void vga_shiftline(int); 73*29a77b73SToomas Soome static void vga_eraseline(void); 74*29a77b73SToomas Soome static void vga_cursor_display(boolean_t); 75*29a77b73SToomas Soome 767c478bd9Sstevel@tonic-gate static void vga_set_crtc(int index, unsigned char val); 777c478bd9Sstevel@tonic-gate static unsigned char vga_get_crtc(int index); 788e6d016fSToomas Soome static void vga_set_atr(int index, unsigned char val); 798e6d016fSToomas Soome static unsigned char vga_get_atr(int index); 807c478bd9Sstevel@tonic-gate 81*29a77b73SToomas Soome static int 82*29a77b73SToomas Soome get_vga_color(void) 83*29a77b73SToomas Soome { 84*29a77b73SToomas Soome int color; 85*29a77b73SToomas Soome uint32_t fg, bg; 86*29a77b73SToomas Soome uint8_t solaris_color_to_pc_color[16] = { 87*29a77b73SToomas Soome 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 88*29a77b73SToomas Soome }; 89*29a77b73SToomas Soome 90*29a77b73SToomas Soome boot_get_color(&fg, &bg); 91*29a77b73SToomas Soome color = solaris_color_to_pc_color[bg] << 4; 92*29a77b73SToomas Soome color |= solaris_color_to_pc_color[fg]; 93*29a77b73SToomas Soome return (color); 94*29a77b73SToomas Soome } 95*29a77b73SToomas Soome 96843e1988Sjohnlev void 97*29a77b73SToomas Soome boot_vga_init(bcons_dev_t *bcons_dev) 988e6d016fSToomas Soome { 998e6d016fSToomas Soome fb_info.terminal.x = VGA_TEXT_COLS; 1008e6d016fSToomas Soome fb_info.terminal.y = VGA_TEXT_ROWS; 101*29a77b73SToomas Soome cons_color = get_vga_color(); 1028e6d016fSToomas Soome 1038e6d016fSToomas Soome #if defined(_BOOT) 1048e6d016fSToomas Soome /* 1058e6d016fSToomas Soome * Note that we have to enable the cursor before clearing the 1068e6d016fSToomas Soome * screen since the cursor position is dependant upon the cursor 1078e6d016fSToomas Soome * skew, which is initialized by vga_cursor_display() 1088e6d016fSToomas Soome */ 1098e6d016fSToomas Soome vga_init(); 1108e6d016fSToomas Soome fb_info.cursor.visible = B_FALSE; 111*29a77b73SToomas Soome vga_cursor_display(B_TRUE); 1128e6d016fSToomas Soome 1138e6d016fSToomas Soome /* 1148e6d016fSToomas Soome * In general we should avoid resetting the display during the boot, 1158e6d016fSToomas Soome * we may have valueable messages there, this why the "native" loader 1168e6d016fSToomas Soome * boot does pass the console state down to kernel and we do try to 1178e6d016fSToomas Soome * pick the state. However, the loader is not the only way to boot. 1188e6d016fSToomas Soome * The non-native boot loaders do not implement the smooth console. 1198e6d016fSToomas Soome * If we have no information about cursor location, we will get value 1208e6d016fSToomas Soome * (0, 0) and that means we better clear the screen. 1218e6d016fSToomas Soome */ 1228e6d016fSToomas Soome if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) 1238e6d016fSToomas Soome vga_clear(cons_color); 1248e6d016fSToomas Soome vga_setpos(fb_info.cursor.pos.y, fb_info.cursor.pos.x); 1258e6d016fSToomas Soome #endif /* _BOOT */ 126*29a77b73SToomas Soome 127*29a77b73SToomas Soome bcons_dev->bd_putchar = vga_drawc; 128*29a77b73SToomas Soome bcons_dev->bd_eraseline = vga_eraseline; 129*29a77b73SToomas Soome bcons_dev->bd_cursor = vga_cursor_display; 130*29a77b73SToomas Soome bcons_dev->bd_setpos = vga_setpos; 131*29a77b73SToomas Soome bcons_dev->bd_shift = vga_shiftline; 1328e6d016fSToomas Soome } 1338e6d016fSToomas Soome 1348e6d016fSToomas Soome static void 1358e6d016fSToomas Soome vga_init(void) 1368e6d016fSToomas Soome { 1378e6d016fSToomas Soome unsigned char val; 1388e6d016fSToomas Soome 1398e6d016fSToomas Soome /* set 16bit colors */ 1408e6d016fSToomas Soome val = vga_get_atr(VGA_ATR_MODE); 1418e6d016fSToomas Soome val &= ~VGA_ATR_MODE_BLINK; 1428e6d016fSToomas Soome val &= ~VGA_ATR_MODE_9WIDE; 1438e6d016fSToomas Soome vga_set_atr(VGA_ATR_MODE, val); 1448e6d016fSToomas Soome } 1458e6d016fSToomas Soome 1468e6d016fSToomas Soome static void 147*29a77b73SToomas Soome vga_cursor_display(boolean_t visible) 148843e1988Sjohnlev { 149843e1988Sjohnlev unsigned char val, msl; 150843e1988Sjohnlev 151*29a77b73SToomas Soome if (fb_info.cursor.visible == visible) 152*29a77b73SToomas Soome return; 153*29a77b73SToomas Soome 154843e1988Sjohnlev /* 155843e1988Sjohnlev * Figure out the maximum scan line value. We need this to set the 156843e1988Sjohnlev * cursor size. 157843e1988Sjohnlev */ 158843e1988Sjohnlev msl = vga_get_crtc(VGA_CRTC_MAX_S_LN) & 0x1f; 159843e1988Sjohnlev 160843e1988Sjohnlev /* 161843e1988Sjohnlev * Enable the cursor and set it's size. Preserve the upper two 162843e1988Sjohnlev * bits of the control register. 163843e1988Sjohnlev * - Bits 0-4 are the starting scan line of the cursor. 164843e1988Sjohnlev * Scanning is done from top-to-bottom. The top-most scan 165843e1988Sjohnlev * line is 0 and the bottom most scan line is the maximum scan 166843e1988Sjohnlev * line value. 167843e1988Sjohnlev * - Bit 5 is the cursor disable bit. 168843e1988Sjohnlev */ 1698e6d016fSToomas Soome val = vga_get_crtc(VGA_CRTC_CSSL) & 0xc0; 170*29a77b73SToomas Soome 171*29a77b73SToomas Soome if (visible == B_FALSE) 172*29a77b73SToomas Soome val |= (1 << 5); 173*29a77b73SToomas Soome 1748e6d016fSToomas Soome vga_set_crtc(VGA_CRTC_CSSL, val); 175843e1988Sjohnlev 176843e1988Sjohnlev /* 177843e1988Sjohnlev * Continue setting the cursors size. 178843e1988Sjohnlev * - Bits 0-4 are the ending scan line of the cursor. 179843e1988Sjohnlev * Scanning is done from top-to-bottom. The top-most scan 180843e1988Sjohnlev * line is 0 and the bottom most scan line is the maximum scan 181843e1988Sjohnlev * line value. 182843e1988Sjohnlev * - Bits 5-6 are the cursor skew. 183843e1988Sjohnlev */ 184843e1988Sjohnlev vga_set_crtc(VGA_CRTC_CESL, msl); 185843e1988Sjohnlev } 186843e1988Sjohnlev 1878e6d016fSToomas Soome static void 188*29a77b73SToomas Soome vga_eraseline_impl(int x, int y, int color) 1897c478bd9Sstevel@tonic-gate { 190*29a77b73SToomas Soome unsigned short val, *buf; 1917c478bd9Sstevel@tonic-gate int i; 1927c478bd9Sstevel@tonic-gate 193*29a77b73SToomas Soome buf = VGA_SCREEN + x + y * VGA_TEXT_COLS; 1947c478bd9Sstevel@tonic-gate val = (color << 8) | ' '; 195*29a77b73SToomas Soome for (i = x; i < VGA_TEXT_COLS; i++) 196*29a77b73SToomas Soome buf[i] = val; 197*29a77b73SToomas Soome } 198*29a77b73SToomas Soome 199*29a77b73SToomas Soome static void 200*29a77b73SToomas Soome vga_eraseline(void) 201*29a77b73SToomas Soome { 202*29a77b73SToomas Soome int x, y; 203*29a77b73SToomas Soome 204*29a77b73SToomas Soome x = fb_info.cursor.pos.x; 205*29a77b73SToomas Soome y = fb_info.cursor.pos.y; 206*29a77b73SToomas Soome vga_eraseline_impl(x, y, cons_color); 207*29a77b73SToomas Soome } 2087c478bd9Sstevel@tonic-gate 209*29a77b73SToomas Soome static void 210*29a77b73SToomas Soome vga_shiftline(int chars) 211*29a77b73SToomas Soome { 212*29a77b73SToomas Soome unsigned short *src, *dst; 213*29a77b73SToomas Soome int x, y, len; 214*29a77b73SToomas Soome 215*29a77b73SToomas Soome x = fb_info.cursor.pos.x; 216*29a77b73SToomas Soome y = fb_info.cursor.pos.y; 217*29a77b73SToomas Soome len = VGA_TEXT_COLS - x - chars; 218*29a77b73SToomas Soome if (len <= 0) 219*29a77b73SToomas Soome return; 220*29a77b73SToomas Soome 221*29a77b73SToomas Soome src = VGA_SCREEN + x + y * VGA_TEXT_COLS; 222*29a77b73SToomas Soome dst = src + chars; 223*29a77b73SToomas Soome if (dst <= src) { 224*29a77b73SToomas Soome do { 225*29a77b73SToomas Soome *dst++ = *src++; 226*29a77b73SToomas Soome } while (--len != 0); 227*29a77b73SToomas Soome } else { 228*29a77b73SToomas Soome dst += len; 229*29a77b73SToomas Soome src += len; 230*29a77b73SToomas Soome do { 231*29a77b73SToomas Soome *--dst = *--src; 232*29a77b73SToomas Soome } while (--len != 0); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 236*29a77b73SToomas Soome static void 237*29a77b73SToomas Soome vga_clear(int color) 238*29a77b73SToomas Soome { 239*29a77b73SToomas Soome int i; 240*29a77b73SToomas Soome 241*29a77b73SToomas Soome for (i = 0; i < VGA_TEXT_ROWS; i++) 242*29a77b73SToomas Soome vga_eraseline_impl(0, i, color); 243*29a77b73SToomas Soome } 244*29a77b73SToomas Soome 245*29a77b73SToomas Soome static void 246*29a77b73SToomas Soome vga_drawc(int c) 2477c478bd9Sstevel@tonic-gate { 2487c478bd9Sstevel@tonic-gate int row; 2497c478bd9Sstevel@tonic-gate int col; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate vga_getpos(&row, &col); 252*29a77b73SToomas Soome 253*29a77b73SToomas Soome if (c == '\n') { 254*29a77b73SToomas Soome if (row < fb_info.terminal.y - 1) 255*29a77b73SToomas Soome vga_setpos(row + 1, col); 256*29a77b73SToomas Soome else 257*29a77b73SToomas Soome vga_scroll(cons_color); 258*29a77b73SToomas Soome return; 259*29a77b73SToomas Soome } 260*29a77b73SToomas Soome 261*29a77b73SToomas Soome /* 262*29a77b73SToomas Soome * VGA_SCREEN is an array of 16-bit unsigned ints, we do let 263*29a77b73SToomas Soome * the compiler to take care of truncation here. 264*29a77b73SToomas Soome */ 265*29a77b73SToomas Soome VGA_SCREEN[row * VGA_TEXT_COLS + col] = (cons_color << 8) | c; 266*29a77b73SToomas Soome 267*29a77b73SToomas Soome if (col < VGA_TEXT_COLS - 1) 268*29a77b73SToomas Soome vga_setpos(row, col + 1); 269*29a77b73SToomas Soome else if (row < VGA_TEXT_ROWS - 1) 270*29a77b73SToomas Soome vga_setpos(row + 1, 0); 271*29a77b73SToomas Soome else { 272*29a77b73SToomas Soome vga_setpos(row, 0); 273*29a77b73SToomas Soome vga_scroll(cons_color); 274*29a77b73SToomas Soome } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 277*29a77b73SToomas Soome static void 2787c478bd9Sstevel@tonic-gate vga_scroll(int color) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate int i; 2817c478bd9Sstevel@tonic-gate 282*29a77b73SToomas Soome for (i = 0; i < (VGA_TEXT_ROWS - 1) * VGA_TEXT_COLS; i++) { 2837c478bd9Sstevel@tonic-gate VGA_SCREEN[i] = VGA_SCREEN[i + VGA_TEXT_COLS]; 2847c478bd9Sstevel@tonic-gate } 285*29a77b73SToomas Soome vga_eraseline_impl(0, VGA_TEXT_ROWS - 1, color); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 288*29a77b73SToomas Soome static void 2897c478bd9Sstevel@tonic-gate vga_setpos(int row, int col) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate int off; 2927c478bd9Sstevel@tonic-gate 293*29a77b73SToomas Soome if (row < 0) 294*29a77b73SToomas Soome row = 0; 295*29a77b73SToomas Soome if (row >= fb_info.terminal.y) 296*29a77b73SToomas Soome row = fb_info.terminal.y - 1; 297*29a77b73SToomas Soome if (col < 0) 298*29a77b73SToomas Soome col = 0; 299*29a77b73SToomas Soome if (col >= fb_info.terminal.x) 300*29a77b73SToomas Soome col = fb_info.terminal.x - 1; 301*29a77b73SToomas Soome 3027c478bd9Sstevel@tonic-gate off = row * VGA_TEXT_COLS + col; 3037c478bd9Sstevel@tonic-gate vga_set_crtc(VGA_CRTC_CLAH, off >> 8); 3047c478bd9Sstevel@tonic-gate vga_set_crtc(VGA_CRTC_CLAL, off & 0xff); 3058e6d016fSToomas Soome 3068e6d016fSToomas Soome fb_info.cursor.pos.y = row; 3078e6d016fSToomas Soome fb_info.cursor.pos.x = col; 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 310*29a77b73SToomas Soome static void 3117c478bd9Sstevel@tonic-gate vga_getpos(int *row, int *col) 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate int off; 3147c478bd9Sstevel@tonic-gate 315843e1988Sjohnlev off = (vga_get_crtc(VGA_CRTC_CLAH) << 8) + vga_get_crtc(VGA_CRTC_CLAL); 3167c478bd9Sstevel@tonic-gate *row = off / VGA_TEXT_COLS; 3177c478bd9Sstevel@tonic-gate *col = off % VGA_TEXT_COLS; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3208e6d016fSToomas Soome static void 3218e6d016fSToomas Soome vga_set_atr(int index, unsigned char val) 3228e6d016fSToomas Soome { 3238e6d016fSToomas Soome (void) inb(VGA_REG_ADDR + CGA_STAT); 3248e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_ATR_AD, index); 3258e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_ATR_AD, val); 3268e6d016fSToomas Soome 3278e6d016fSToomas Soome (void) inb(VGA_REG_ADDR + CGA_STAT); 3288e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT); 3298e6d016fSToomas Soome } 3308e6d016fSToomas Soome 3318e6d016fSToomas Soome static unsigned char 3328e6d016fSToomas Soome vga_get_atr(int index) 3338e6d016fSToomas Soome { 3348e6d016fSToomas Soome unsigned char val; 3358e6d016fSToomas Soome 3368e6d016fSToomas Soome (void) inb(VGA_REG_ADDR + CGA_STAT); 3378e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_ATR_AD, index); 3388e6d016fSToomas Soome val = inb(VGA_REG_ADDR + VGA_ATR_DATA); 3398e6d016fSToomas Soome 3408e6d016fSToomas Soome (void) inb(VGA_REG_ADDR + CGA_STAT); 3418e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT); 3428e6d016fSToomas Soome 3438e6d016fSToomas Soome return (val); 3448e6d016fSToomas Soome } 3458e6d016fSToomas Soome 3467c478bd9Sstevel@tonic-gate static void 3477c478bd9Sstevel@tonic-gate vga_set_crtc(int index, unsigned char val) 3487c478bd9Sstevel@tonic-gate { 3498e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_CRTC_ADR, index); 3508e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_CRTC_DATA, val); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate static unsigned char 3547c478bd9Sstevel@tonic-gate vga_get_crtc(int index) 3557c478bd9Sstevel@tonic-gate { 3568e6d016fSToomas Soome outb(VGA_REG_ADDR + VGA_CRTC_ADR, index); 3578e6d016fSToomas Soome return (inb(VGA_REG_ADDR + VGA_CRTC_DATA)); 3587c478bd9Sstevel@tonic-gate } 359