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 5*843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6*843e1988Sjohnlev * 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*843e1988Sjohnlev * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <sys/controlregs.h> 317c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 327c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h> 337c478bd9Sstevel@tonic-gate #include <sys/bootregs.h> 347c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 357c478bd9Sstevel@tonic-gate #include <sys/conf.h> 367c478bd9Sstevel@tonic-gate #include <sys/promif.h> 377c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 407c478bd9Sstevel@tonic-gate #include <sys/biosdisk.h> 417c478bd9Sstevel@tonic-gate #include <sys/psw.h> 42*843e1988Sjohnlev #if defined(__xpv) 43*843e1988Sjohnlev #include <sys/hypervisor.h> 44*843e1988Sjohnlev #endif 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* hard code realmode memory address for now */ 487c478bd9Sstevel@tonic-gate #define BIOS_RES_BUFFER_ADDR 0x7000 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #define BIOSDEV_NUM 8 517c478bd9Sstevel@tonic-gate #define STARTING_DRVNUM 0x80 527c478bd9Sstevel@tonic-gate #define FP_OFF(fp) (((uintptr_t)(fp)) & 0xFFFF) 537c478bd9Sstevel@tonic-gate #define FP_SEG(fp) ((((uintptr_t)(fp)) >> 16) & 0xFFFF) 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #ifdef DEBUG 567c478bd9Sstevel@tonic-gate int biosdebug = 0; 577c478bd9Sstevel@tonic-gate #define dprintf(fmt) \ 587c478bd9Sstevel@tonic-gate if (biosdebug) \ 597c478bd9Sstevel@tonic-gate prom_printf fmt 607c478bd9Sstevel@tonic-gate #else 617c478bd9Sstevel@tonic-gate #define dprintf(fmt) 627c478bd9Sstevel@tonic-gate #endif 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate biosdev_data_t biosdev_info[BIOSDEV_NUM]; /* from 0x80 to 0x87 */ 657c478bd9Sstevel@tonic-gate int dobiosdev = 1; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static int bios_check_extension_present(uchar_t); 697c478bd9Sstevel@tonic-gate static int get_dev_params(uchar_t); 707c478bd9Sstevel@tonic-gate static int read_firstblock(uchar_t drivenum); 717c478bd9Sstevel@tonic-gate static int drive_present(uchar_t drivenum); 727c478bd9Sstevel@tonic-gate static void reset_disk(uchar_t drivenum); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate void 767c478bd9Sstevel@tonic-gate startup_bios_disk() 777c478bd9Sstevel@tonic-gate { 787c478bd9Sstevel@tonic-gate uchar_t drivenum; 797c478bd9Sstevel@tonic-gate int got_devparams = 0; 807c478bd9Sstevel@tonic-gate int got_first_block = 0; 817c478bd9Sstevel@tonic-gate uchar_t name[20]; 827c478bd9Sstevel@tonic-gate dev_info_t *devi; 837c478bd9Sstevel@tonic-gate 84*843e1988Sjohnlev #if defined(__xpv) 85*843e1988Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) 86*843e1988Sjohnlev return; 87*843e1988Sjohnlev #endif 88*843e1988Sjohnlev 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 977c478bd9Sstevel@tonic-gate got_devparams = get_dev_params(drivenum); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate if ((got_first_block = read_firstblock(drivenum)) == 0) { 1007c478bd9Sstevel@tonic-gate /* retry */ 1017c478bd9Sstevel@tonic-gate got_first_block = read_firstblock(drivenum); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate if (got_devparams || got_first_block) { 1057c478bd9Sstevel@tonic-gate (void) sprintf((char *)name, "biosdev-0x%x", drivenum); 1067c478bd9Sstevel@tonic-gate devi = ddi_root_node(); 1077c478bd9Sstevel@tonic-gate (void) e_ddi_prop_update_byte_array(DDI_DEV_T_NONE, 1087c478bd9Sstevel@tonic-gate devi, (char *)name, 1097c478bd9Sstevel@tonic-gate (uchar_t *)&biosdev_info[drivenum - 0x80], 1107c478bd9Sstevel@tonic-gate sizeof (biosdev_data_t)); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate static int 1167c478bd9Sstevel@tonic-gate bios_check_extension_present(uchar_t drivenum) 1177c478bd9Sstevel@tonic-gate { 1187c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 1197c478bd9Sstevel@tonic-gate extern struct bootops *bootops; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate rp.eax.word.ax = 0x4100; 1227c478bd9Sstevel@tonic-gate rp.ebx.word.bx = 0x55AA; 1237c478bd9Sstevel@tonic-gate rp.edx.word.dx = drivenum; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* make sure we have extension support */ 1267c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || (rp.ebx.word.bx != 0xAA55)) { 1297c478bd9Sstevel@tonic-gate dprintf(("bios_check_extension_present int13 fn 41 " 1307c478bd9Sstevel@tonic-gate "failed %d bx = %x\n", rp.eflags, rp.ebx.word.bx)); 1317c478bd9Sstevel@tonic-gate return (0); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate if ((rp.ecx.word.cx & 0x7) == 0) { 1357c478bd9Sstevel@tonic-gate dprintf(("bios_check_extension_present get device parameters " 1367c478bd9Sstevel@tonic-gate "not supported cx = %x\n", rp.ecx.word.cx)); 1377c478bd9Sstevel@tonic-gate return (0); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate return (1); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static int 1447c478bd9Sstevel@tonic-gate get_dev_params(uchar_t drivenum) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 1477c478bd9Sstevel@tonic-gate fn48_t *bufp; 1487c478bd9Sstevel@tonic-gate extern struct bootops *bootops; 1497c478bd9Sstevel@tonic-gate int i; 1507c478bd9Sstevel@tonic-gate int index; 15103859504Sjg uchar_t *tmp; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate dprintf(("In get_dev_params\n")); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (bios_check_extension_present(drivenum) == 0) 1567c478bd9Sstevel@tonic-gate return (0); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate bufp = (fn48_t *)BIOS_RES_BUFFER_ADDR; 1597c478bd9Sstevel@tonic-gate 16003859504Sjg /* 16103859504Sjg * We cannot use bzero here as we're initializing data 16203859504Sjg * at an address below kernel base. 16303859504Sjg */ 1647c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (*bufp); i++) 1657c478bd9Sstevel@tonic-gate ((uchar_t *)bufp)[i] = 0; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate bufp->buflen = sizeof (*bufp); 1687c478bd9Sstevel@tonic-gate rp.eax.word.ax = 0x4800; 1697c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate rp.esi.word.si = (uint16_t)FP_OFF((uint_t)(uintptr_t)bufp); 1727c478bd9Sstevel@tonic-gate rp.ds = FP_SEG((uint_t)(uintptr_t)bufp); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if ((rp.eflags & PS_C) != 0) { 1777c478bd9Sstevel@tonic-gate dprintf(("EDD FAILED on drive eflag = %x ah= %x\n", 1787c478bd9Sstevel@tonic-gate rp.eflags, rp.eax.byte.ah)); 1797c478bd9Sstevel@tonic-gate return (0); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate index = drivenum - 0x80; 1837c478bd9Sstevel@tonic-gate biosdev_info[index].edd_valid = 1; 18403859504Sjg 18503859504Sjg /* 18603859504Sjg * Some compilers turn a structure copy into a call 18703859504Sjg * to memcpy. Since we are copying data below kernel 18803859504Sjg * base intentionally, and memcpy asserts that's not 18903859504Sjg * the case, we do the copy manually here. 19003859504Sjg */ 19103859504Sjg tmp = (uchar_t *)&biosdev_info[index].fn48_dev_params; 19203859504Sjg for (i = 0; i < sizeof (*bufp); i++) 19303859504Sjg tmp[i] = ((uchar_t *)bufp)[i]; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate return (1); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate static int 1997c478bd9Sstevel@tonic-gate drive_present(uchar_t drivenum) 2007c478bd9Sstevel@tonic-gate { 2017c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate rp.eax.byte.ah = 0x8; /* get params */ 2047c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || rp.eax.byte.ah != 0) { 2097c478bd9Sstevel@tonic-gate dprintf(("drive not present drivenum %x eflag %x ah %x\n", 2107c478bd9Sstevel@tonic-gate drivenum, rp.eflags, rp.eax.byte.ah)); 2117c478bd9Sstevel@tonic-gate return (0); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate dprintf(("drive-present %x\n", drivenum)); 2157c478bd9Sstevel@tonic-gate return (1); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate static void 2207c478bd9Sstevel@tonic-gate reset_disk(uchar_t drivenum) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 2237c478bd9Sstevel@tonic-gate int status; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate rp.eax.byte.ah = 0x0; /* reset disk */ 2267c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate status = rp.eax.byte.ah; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || status != 0) 2337c478bd9Sstevel@tonic-gate dprintf(("Bad disk reset driv %x, status %x\n", drivenum, 2347c478bd9Sstevel@tonic-gate status)); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* Get first block */ 2387c478bd9Sstevel@tonic-gate static int 2397c478bd9Sstevel@tonic-gate read_firstblock(uchar_t drivenum) 2407c478bd9Sstevel@tonic-gate { 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate struct bop_regs rp = {0}; 2437c478bd9Sstevel@tonic-gate caddr_t bufp; 2447c478bd9Sstevel@tonic-gate uchar_t status; 2457c478bd9Sstevel@tonic-gate int i, index; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate reset_disk(drivenum); 2497c478bd9Sstevel@tonic-gate bufp = (caddr_t)BIOS_RES_BUFFER_ADDR; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate rp.eax.byte.ah = 0x2; /* Read disk */ 2537c478bd9Sstevel@tonic-gate rp.eax.byte.al = 1; /* nsect */ 2547c478bd9Sstevel@tonic-gate rp.ecx.byte.ch = 0; /* cyl & 0xff */ 2557c478bd9Sstevel@tonic-gate rp.ecx.byte.cl = 1; /* cyl >> 2 & 0xc0 (sector number) */ 2567c478bd9Sstevel@tonic-gate rp.edx.byte.dh = 0; /* head */ 2577c478bd9Sstevel@tonic-gate rp.edx.byte.dl = drivenum; /* drivenum */ 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate /* es:bx is buf address */ 2607c478bd9Sstevel@tonic-gate rp.ebx.word.bx = (uint16_t)FP_OFF((uint_t)(uintptr_t)bufp); 2617c478bd9Sstevel@tonic-gate rp.es = FP_SEG((uint_t)(uintptr_t)bufp); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate BOP_DOINT(bootops, 0x13, &rp); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate status = rp.eax.byte.ah; 2667c478bd9Sstevel@tonic-gate if (((rp.eflags & PS_C) != 0) || status != 0) { 2677c478bd9Sstevel@tonic-gate dprintf(("read_firstblock AH not clear %x \n", status)); 2687c478bd9Sstevel@tonic-gate return (0); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate dprintf(("drivenum %x uid at 0x1b8 is %x\n", drivenum, 2727c478bd9Sstevel@tonic-gate *(uint32_t *)(bufp +0x1b8))); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate index = drivenum - 0x80; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate biosdev_info[index].first_block_valid = 1; 2777c478bd9Sstevel@tonic-gate for (i = 0; i < 512; i++) 2787c478bd9Sstevel@tonic-gate biosdev_info[index].first_block[i] = *((uchar_t *)bufp + i); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate return (1); 2817c478bd9Sstevel@tonic-gate } 282