176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ----------------------------------------------------------------------- * 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright 2009 Shao Miller - All Rights Reserved 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or modify 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it under the terms of the GNU General Public License as published by 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Boston MA 02111-1307, USA; either version 2 of the License, or 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (at your option) any later version; incorporated herein by reference. 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ----------------------------------------------------------------------- */ 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * dskprobe.c 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Routines for probing BIOS disk drives 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Change to 1 for debugging */ 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define DBG_DSKPROBE 0 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "memdisk.h" 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bda.h" 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "conio.h" 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function type for printf() */ 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantypedef int (f_printf) (const char *, ...); 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Dummy printf() that does nothing */ 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_printf no_printf; 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_printf *dskprobe_printfs[] = { no_printf, printf }; 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define dskprobe_printf (dskprobe_printfs[DBG_DSKPROBE]) 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void dskprobe_pause(com32sys_t *); 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Probe routine function type */ 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantypedef int (f_probe) (uint8_t, com32sys_t *); 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_probe probe_int13h_08h, probe_int13h_15h, probe_int13h_41h; 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* We will probe a BIOS drive number using INT 0x13, AH == func */ 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void probe_any(uint8_t func, uint8_t drive, com32sys_t * regs) 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->eax.b[1] = func; /* AH == sub-function for probe */ 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->edx.b[0] = drive; /* DL == drive number to probe */ 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman intcall(0x13, regs, regs); 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Determine if the return from probe_int13h_01h indicates a failure; a 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return of zero indicates no known failure. 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_01h_fail(int istatus) 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status = 0; 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (istatus >= 256) 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = istatus; 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (istatus) { 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 1: status = istatus; 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return status; 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x01: Get status of last command. 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_01h(uint8_t drive) 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman com32sys_t regs; 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(®s, 0, sizeof regs); 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman probe_any(0x01, drive, ®s); 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = (regs.eflags.l & 1) * 256 + regs.eax.b[1]; 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf(" AH01: CF%d AH%02x", regs.eflags.l & 1, regs.eax.b[1]); 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return status; 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x08: Get drive parameters. 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_08h(uint8_t drive, com32sys_t * regs) 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int present; 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(regs, 0, sizeof *regs); 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman probe_any(0x08, drive, regs); 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf(" AH08: CF%d AH%02x AL%02x BL%02x DL%02x ", 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0], 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->ebx.b[0], regs->edx.b[0]); 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman present = !(regs->eflags.l & 1) && !regs->eax.b[1]; 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = probe_int13h_01h(drive); 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman present = present && !(probe_int13h_01h_fail(status)); 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf(" P%d\n", present); 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return present; 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x15: Get disk type. 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_15h(uint8_t drive, com32sys_t * regs) 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int present; 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(regs, 0, sizeof *regs); 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman probe_any(0x15, drive, regs); 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf(" AH15: CF%d AH%02x AL%02x CX%04x DX%04x", 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0], 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->ecx.w[0], regs->edx.w[0]); 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman present = !(regs->eflags.l & 1) && regs->eax.b[1]; 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = probe_int13h_01h(drive); 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman present = present && !(probe_int13h_01h_fail(status)); 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf(" P%d\n", present); 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return present; 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x41: INT 0x13 extensions installation check. 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_41h(uint8_t drive, com32sys_t * regs) 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int present; 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(regs, 0, sizeof *regs); 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->ebx.w[0] = 0x55AA; /* BX == 0x55AA */ 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman probe_any(0x41, drive, regs); 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf(" AH41: CF%d AH%02x BX%04x CX%04x DH%02x", 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->eflags.l & 1, regs->eax.b[1], regs->ebx.w[0], 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->ecx.w[0], regs->edx.b[1]); 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman present = !(regs->eflags.l & 1) && (regs->ebx.w[0] == 0xAA55); 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = probe_int13h_01h(drive); 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman present = present && !(probe_int13h_01h_fail(status)); 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf(" P%d\n", present); 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return present; 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We will probe the BIOS Data Area and count the drives found there. 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This heuristic then assumes that all drives of 'drive's type are 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * found in a contiguous range, and returns 1 if the probed drive 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is less than or equal to the BDA count. 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This particular function's code is derived from code in setup.c by 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * H. Peter Anvin. Please respect that file's copyright for this function 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint probe_bda_drive(uint8_t drive) 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int bios_drives; 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err; 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (drive & 0x80) { 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bios_drives = rdz_8(BIOS_HD_COUNT); /* HDD count */ 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t equip = rdz_8(BIOS_EQUIP); 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (equip & 1) 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bios_drives = (equip >> 6) + 1; /* Floppy count */ 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bios_drives = 0; 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1; 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf("BDA drive %02x? %d, total count: %d\n", drive, err, 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bios_drives); 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We will probe a drive with a few different methods, returning 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the count of succesful probes 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint multi_probe_drive(uint8_t drive) 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int c = 0; 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman com32sys_t regs; 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf("INT 13 DL%02x:\n", drive); 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Only probe the BDA for floppies */ 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (drive & 0x80) { 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman c += probe_int13h_08h(drive, ®s); 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman c += probe_int13h_15h(drive, ®s); 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman c += probe_int13h_41h(drive, ®s); 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman c += probe_bda_drive(drive); 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_pause(®s); 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return c; 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We will probe a contiguous range of BIOS drive, starting with drive 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * number 'start'. We probe with a few different methods, and return 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the first drive which doesn't respond to any of the probes. 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanuint8_t probe_drive_range(uint8_t start) 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t drive = start; 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (multi_probe_drive(drive)) { 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman drive++; 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check for passing the floppy/HDD boundary */ 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((drive & 0x7F) == 0) 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return drive; 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Dummy printf() that does nothing */ 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int no_printf(const char *ignored, ...) 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (void)ignored; 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Pause if we are in debug-mode */ 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void dskprobe_pause(com32sys_t * regs) 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!DBG_DSKPROBE) 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dskprobe_printf("Press a key to continue...\n"); 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(regs, 0, sizeof *regs); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs->eax.w[0] = 0; 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman intcall(0x16, regs, NULL); 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 229