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 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * 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 */ 217c478bd9Sstevel@tonic-gate /* 22*721df51dSSeth Goldberg * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/param.h> 287c478bd9Sstevel@tonic-gate #include <sys/controlregs.h> 297c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 307c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h> 317c478bd9Sstevel@tonic-gate #include <sys/bootregs.h> 327c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 337c478bd9Sstevel@tonic-gate #include <sys/conf.h> 347c478bd9Sstevel@tonic-gate #include <sys/promif.h> 357c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 377c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 387c478bd9Sstevel@tonic-gate #include <sys/biosdisk.h> 397c478bd9Sstevel@tonic-gate #include <sys/psw.h> 40843e1988Sjohnlev #if defined(__xpv) 41843e1988Sjohnlev #include <sys/hypervisor.h> 42843e1988Sjohnlev #endif 437c478bd9Sstevel@tonic-gate 44*721df51dSSeth Goldberg extern int prom_debug; 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* hard code realmode memory address for now */ 477c478bd9Sstevel@tonic-gate #define BIOS_RES_BUFFER_ADDR 0x7000 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define BIOSDEV_NUM 8 507c478bd9Sstevel@tonic-gate #define STARTING_DRVNUM 0x80 517c478bd9Sstevel@tonic-gate #define FP_OFF(fp) (((uintptr_t)(fp)) & 0xFFFF) 527c478bd9Sstevel@tonic-gate #define FP_SEG(fp) ((((uintptr_t)(fp)) >> 16) & 0xFFFF) 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #ifdef DEBUG 557c478bd9Sstevel@tonic-gate int biosdebug = 0; 567c478bd9Sstevel@tonic-gate #define dprintf(fmt) \ 577c478bd9Sstevel@tonic-gate if (biosdebug) \ 587c478bd9Sstevel@tonic-gate prom_printf fmt 597c478bd9Sstevel@tonic-gate #else 607c478bd9Sstevel@tonic-gate #define dprintf(fmt) 617c478bd9Sstevel@tonic-gate #endif 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate biosdev_data_t biosdev_info[BIOSDEV_NUM]; /* from 0x80 to 0x87 */ 647c478bd9Sstevel@tonic-gate int dobiosdev = 1; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static int bios_check_extension_present(uchar_t); 687c478bd9Sstevel@tonic-gate static int get_dev_params(uchar_t); 697c478bd9Sstevel@tonic-gate static int read_firstblock(uchar_t drivenum); 707c478bd9Sstevel@tonic-gate static int drive_present(uchar_t drivenum); 717c478bd9Sstevel@tonic-gate static void reset_disk(uchar_t drivenum); 72*721df51dSSeth Goldberg static int is_eltorito(uchar_t drivenum); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate void 757c478bd9Sstevel@tonic-gate startup_bios_disk() 767c478bd9Sstevel@tonic-gate { 777c478bd9Sstevel@tonic-gate uchar_t drivenum; 787c478bd9Sstevel@tonic-gate int got_devparams = 0; 797c478bd9Sstevel@tonic-gate int got_first_block = 0; 807c478bd9Sstevel@tonic-gate uchar_t name[20]; 817c478bd9Sstevel@tonic-gate dev_info_t *devi; 82*721df51dSSeth Goldberg int extensions; 837c478bd9Sstevel@tonic-gate 84843e1988Sjohnlev #if defined(__xpv) 85843e1988Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) 86843e1988Sjohnlev return; 87843e1988Sjohnlev #endif 88843e1988Sjohnlev 897c478bd9Sstevel@tonic-gate if (dobiosdev == 0) 907c478bd9Sstevel@tonic-gate return; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate for (drivenum = 0x80; drivenum < (0x80 + BIOSDEV_NUM); drivenum++) { 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if (!drive_present(drivenum)) 957c478bd9Sstevel@tonic-gate continue; 967c478bd9Sstevel@tonic-gate 97*721df51dSSeth Goldberg extensions = bios_check_extension_present(drivenum); 98*721df51dSSeth Goldberg 99*721df51dSSeth Goldberg /* 100*721df51dSSeth Goldberg * If we're booting from an Eltorito CD/DVD image, there's 101*721df51dSSeth Goldberg * no need to get the device parameters or read the first block 102*721df51dSSeth Goldberg * because we'll never install onto this device. 103*721df51dSSeth Goldberg */ 104*721df51dSSeth Goldberg if (extensions && is_eltorito(drivenum)) 105*721df51dSSeth Goldberg continue; 106*721df51dSSeth Goldberg 107*721df51dSSeth Goldberg if (extensions && get_dev_params(drivenum)) 108*721df51dSSeth Goldberg got_devparams = 1; 109*721df51dSSeth Goldberg else 110*721df51dSSeth Goldberg got_devparams = 0; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate if ((got_first_block = read_firstblock(drivenum)) == 0) { 1137c478bd9Sstevel@tonic-gate /* retry */ 1147c478bd9Sstevel@tonic-gate got_first_block = read_firstblock(drivenum); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate if (got_devparams || got_first_block) { 1187c478bd9Sstevel@tonic-gate (void) sprintf((char *)name, "biosdev-0x%x", drivenum); 1197c478bd9Sstevel@tonic-gate devi = ddi_root_node(); 1207c478bd9Sstevel@tonic-gate (void) e_ddi_prop_update_byte_array(DDI_DEV_T_NONE, 1217c478bd9Sstevel@tonic-gate devi, (char *)name, 1227c478bd9Sstevel@tonic-gate (uchar_t *)&biosdev_info[drivenum - 0x80], 1237c478bd9Sstevel@tonic-gate sizeof (biosdev_data_t)); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate static int 1297c478bd9Sstevel@tonic-gate bios_check_extension_present(uchar_t drivenum) 1307c478bd9Sstevel@tonic-gate { 1317c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 1327c478bd9Sstevel@tonic-gate extern struct bootops *bootops; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate rp.eax.word.ax = 0x4100; 1357c478bd9Sstevel@tonic-gate rp.ebx.word.bx = 0x55AA; 1367c478bd9Sstevel@tonic-gate rp.edx.word.dx = drivenum; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* make sure we have extension support */ 1397c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || (rp.ebx.word.bx != 0xAA55)) { 1427c478bd9Sstevel@tonic-gate dprintf(("bios_check_extension_present int13 fn 41 " 1437c478bd9Sstevel@tonic-gate "failed %d bx = %x\n", rp.eflags, rp.ebx.word.bx)); 1447c478bd9Sstevel@tonic-gate return (0); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate if ((rp.ecx.word.cx & 0x7) == 0) { 1487c478bd9Sstevel@tonic-gate dprintf(("bios_check_extension_present get device parameters " 1497c478bd9Sstevel@tonic-gate "not supported cx = %x\n", rp.ecx.word.cx)); 1507c478bd9Sstevel@tonic-gate return (0); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate return (1); 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate static int 1577c478bd9Sstevel@tonic-gate get_dev_params(uchar_t drivenum) 1587c478bd9Sstevel@tonic-gate { 1597c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 1607c478bd9Sstevel@tonic-gate fn48_t *bufp; 1617c478bd9Sstevel@tonic-gate extern struct bootops *bootops; 1627c478bd9Sstevel@tonic-gate int i; 1637c478bd9Sstevel@tonic-gate int index; 16403859504Sjg uchar_t *tmp; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate dprintf(("In get_dev_params\n")); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate bufp = (fn48_t *)BIOS_RES_BUFFER_ADDR; 1697c478bd9Sstevel@tonic-gate 17003859504Sjg /* 17103859504Sjg * We cannot use bzero here as we're initializing data 17203859504Sjg * at an address below kernel base. 17303859504Sjg */ 1747c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (*bufp); i++) 1757c478bd9Sstevel@tonic-gate ((uchar_t *)bufp)[i] = 0; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate bufp->buflen = sizeof (*bufp); 1787c478bd9Sstevel@tonic-gate rp.eax.word.ax = 0x4800; 1797c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate rp.esi.word.si = (uint16_t)FP_OFF((uint_t)(uintptr_t)bufp); 1827c478bd9Sstevel@tonic-gate rp.ds = FP_SEG((uint_t)(uintptr_t)bufp); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate if ((rp.eflags & PS_C) != 0) { 1877c478bd9Sstevel@tonic-gate dprintf(("EDD FAILED on drive eflag = %x ah= %x\n", 1887c478bd9Sstevel@tonic-gate rp.eflags, rp.eax.byte.ah)); 1897c478bd9Sstevel@tonic-gate return (0); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate index = drivenum - 0x80; 1937c478bd9Sstevel@tonic-gate biosdev_info[index].edd_valid = 1; 19403859504Sjg 19503859504Sjg /* 19603859504Sjg * Some compilers turn a structure copy into a call 19703859504Sjg * to memcpy. Since we are copying data below kernel 19803859504Sjg * base intentionally, and memcpy asserts that's not 19903859504Sjg * the case, we do the copy manually here. 20003859504Sjg */ 20103859504Sjg tmp = (uchar_t *)&biosdev_info[index].fn48_dev_params; 20203859504Sjg for (i = 0; i < sizeof (*bufp); i++) 20303859504Sjg tmp[i] = ((uchar_t *)bufp)[i]; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate return (1); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate static int 2097c478bd9Sstevel@tonic-gate drive_present(uchar_t drivenum) 2107c478bd9Sstevel@tonic-gate { 2117c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate rp.eax.byte.ah = 0x8; /* get params */ 2147c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || rp.eax.byte.ah != 0) { 2197c478bd9Sstevel@tonic-gate dprintf(("drive not present drivenum %x eflag %x ah %x\n", 2207c478bd9Sstevel@tonic-gate drivenum, rp.eflags, rp.eax.byte.ah)); 2217c478bd9Sstevel@tonic-gate return (0); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate dprintf(("drive-present %x\n", drivenum)); 2257c478bd9Sstevel@tonic-gate return (1); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate static void 2297c478bd9Sstevel@tonic-gate reset_disk(uchar_t drivenum) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 2327c478bd9Sstevel@tonic-gate int status; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate rp.eax.byte.ah = 0x0; /* reset disk */ 2357c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate status = rp.eax.byte.ah; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || status != 0) 2427c478bd9Sstevel@tonic-gate dprintf(("Bad disk reset driv %x, status %x\n", drivenum, 2437c478bd9Sstevel@tonic-gate status)); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* Get first block */ 2477c478bd9Sstevel@tonic-gate static int 2487c478bd9Sstevel@tonic-gate read_firstblock(uchar_t drivenum) 2497c478bd9Sstevel@tonic-gate { 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 2527c478bd9Sstevel@tonic-gate caddr_t bufp; 2537c478bd9Sstevel@tonic-gate uchar_t status; 2547c478bd9Sstevel@tonic-gate int i, index; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate reset_disk(drivenum); 2587c478bd9Sstevel@tonic-gate bufp = (caddr_t)BIOS_RES_BUFFER_ADDR; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate rp.eax.byte.ah = 0x2; /* Read disk */ 2627c478bd9Sstevel@tonic-gate rp.eax.byte.al = 1; /* nsect */ 2637c478bd9Sstevel@tonic-gate rp.ecx.byte.ch = 0; /* cyl & 0xff */ 2647c478bd9Sstevel@tonic-gate rp.ecx.byte.cl = 1; /* cyl >> 2 & 0xc0 (sector number) */ 2657c478bd9Sstevel@tonic-gate rp.edx.byte.dh = 0; /* head */ 2667c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; /* drivenum */ 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* es:bx is buf address */ 2697c478bd9Sstevel@tonic-gate rp.ebx.word.bx = (uint16_t)FP_OFF((uint_t)(uintptr_t)bufp); 2707c478bd9Sstevel@tonic-gate rp.es = FP_SEG((uint_t)(uintptr_t)bufp); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate status = rp.eax.byte.ah; 2757c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || status != 0) { 2767c478bd9Sstevel@tonic-gate dprintf(("read_firstblock AH not clear %x \n", status)); 2777c478bd9Sstevel@tonic-gate return (0); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate dprintf(("drivenum %x uid at 0x1b8 is %x\n", drivenum, 2817c478bd9Sstevel@tonic-gate *(uint32_t *)(bufp +0x1b8))); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate index = drivenum - 0x80; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate biosdev_info[index].first_block_valid = 1; 2867c478bd9Sstevel@tonic-gate for (i = 0; i < 512; i++) 2877c478bd9Sstevel@tonic-gate biosdev_info[index].first_block[i] = *((uchar_t *)bufp + i); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate return (1); 2907c478bd9Sstevel@tonic-gate } 291*721df51dSSeth Goldberg 292*721df51dSSeth Goldberg static int 293*721df51dSSeth Goldberg is_eltorito(uchar_t drivenum) 294*721df51dSSeth Goldberg { 295*721df51dSSeth Goldberg struct bop_regs rp = {0}; 296*721df51dSSeth Goldberg fn4b_t *bufp; 297*721df51dSSeth Goldberg extern struct bootops *bootops; 298*721df51dSSeth Goldberg int i; 299*721df51dSSeth Goldberg 300*721df51dSSeth Goldberg dprintf(("In is_eltorito\n")); 301*721df51dSSeth Goldberg 302*721df51dSSeth Goldberg bufp = (fn4b_t *)BIOS_RES_BUFFER_ADDR; 303*721df51dSSeth Goldberg 304*721df51dSSeth Goldberg /* 305*721df51dSSeth Goldberg * We cannot use bzero here as we're initializing data 306*721df51dSSeth Goldberg * at an address below kernel base. 307*721df51dSSeth Goldberg */ 308*721df51dSSeth Goldberg for (i = 0; i < sizeof (*bufp); i++) 309*721df51dSSeth Goldberg ((uchar_t *)bufp)[i] = 0; 310*721df51dSSeth Goldberg 311*721df51dSSeth Goldberg bufp->pkt_size = sizeof (*bufp); 312*721df51dSSeth Goldberg rp.eax.word.ax = 0x4b01; 313*721df51dSSeth Goldberg rp.edx.byte.dl = drivenum; 314*721df51dSSeth Goldberg 315*721df51dSSeth Goldberg rp.esi.word.si = (uint16_t)FP_OFF((uint_t)(uintptr_t)bufp); 316*721df51dSSeth Goldberg rp.ds = FP_SEG((uint_t)(uintptr_t)bufp); 317*721df51dSSeth Goldberg 318*721df51dSSeth Goldberg BOP_DOINT(bootops, 0x13, &rp); 319*721df51dSSeth Goldberg 320*721df51dSSeth Goldberg if ((rp.eflags & PS_C) != 0 || bufp->drivenum != drivenum) { 321*721df51dSSeth Goldberg dprintf(("fn 0x4b01 FAILED on drive " 322*721df51dSSeth Goldberg "eflags=%x ah=%x drivenum=%x\n", 323*721df51dSSeth Goldberg rp.eflags, rp.eax.byte.ah, bufp->drivenum)); 324*721df51dSSeth Goldberg return (0); 325*721df51dSSeth Goldberg } 326*721df51dSSeth Goldberg 327*721df51dSSeth Goldberg if (prom_debug) 328*721df51dSSeth Goldberg prom_printf("INT13 FN4B01 mtype => %x", bufp->boot_mtype); 329*721df51dSSeth Goldberg 330*721df51dSSeth Goldberg return (1); 331*721df51dSSeth Goldberg } 332