📄 ide.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name: ide.c
Abstract: Boot loader IDE/ATA access functions.
Functions:
ide_reset - Reset IDE drive.
id_drive - Locate/identify drive.
lba_to_pchs - Convert LBA address to Physical CHS.
read_sector - Read the contents of a disk sector.
init_ide - Initialize IDE drive.
load_image_ide - Load OS image from drive.
OEMHDDPlatformInit - Blcommon interface functions.
OEMHDDPreDownload - "
OEMHDDReadData - "
OEMHDDLaunch - "
Notes:
Assumptions:
- only primary master drive is supported
- FAT16
- file op routines only work on a single file at a time
- kernel image is in the root directory with the bootloader image
--*/
#include <windows.h>
#include <memorymap.h>
#include <blcommon.h>
#include <halether.h>
#include <debugtimer.h>
#include "ide.h"
#include "fat.h"
//#include "bldr.h"
// Global variables.
//
UCHAR g_bsect[SECTOR_SIZE];
ULONG g_sectorsread=0;
UCHAR g_bstartcounting=0;
//STATUSBAR g_statbar;
BOOL g_bLBAMode = FALSE;
// Function prototypes.
//
//int create_statusbar(PSTATUSBAR pbar, ULONG sval, ULONG eval);
//int update_statusbar(PSTATUSBAR pbar, ULONG cval);
//BOOL InitNIC(void);
// Externs.
//
extern FILEINFO g_fileinfo;
#define KIMAGE_NAME "nk.bin" // Kernel image name.
int ide_reset(void)
{
DEBUGMSG(ZONE_INFO, (TEXT("ide_reset: entered.\r\n")));
WAIT_IDE_BUSY;
WRITE_IDE_UCHAR(IDE_ALT_CTRL_REG, (IDE_ALT_CTRL_SRST | IDE_ALT_CTRL_DSBL_INTR));
//WAIT_IDE_NOT_BUSY;
//
// The IDE specification says wait 4 Milliseconds and nothing about waiting for
// busy.
//
DelayInMsec(4);
WRITE_IDE_UCHAR(IDE_ALT_CTRL_REG, IDE_ALT_CTRL_DSBL_INTR);
WAIT_IDE_NOT_DRDY;
WAIT_IDE_BUSY;
if(IS_IDE_ERROR)
{
RETAILMSG(1, (TEXT("WARNING: Drive reset failed.\r\n")));
}
DEBUGMSG(ZONE_INFO, (TEXT("ide_reset: done.\r\n")));
return(0);
}
int id_drive(void)
{
USHORT cnt=0;
drv_id_hdr hdr;
DEBUGMSG(ZONE_BOOTPROG, (TEXT("B6\r\n")));
// Select the drive.
//
WRITE_IDE_UCHAR(IDE_DRVHD_REG, IDE_HEAD_DRIVE_1);
// Reset the drive.
//
if (ide_reset())
return(-1);
DEBUGMSG(ZONE_BOOTPROG, (TEXT("B7\r\n")));
WAIT_IDE_BUSY;
// Select the drive.
//
WRITE_IDE_UCHAR(IDE_DRVHD_REG, IDE_HEAD_DRIVE_1);
DEBUGMSG(ZONE_BOOTPROG, (TEXT("B8\r\n")));
// Identify the drive.
//
memset(&hdr, 0, sizeof(drv_id_hdr));
WAIT_IDE_BUSY;
WAIT_IDE_NOT_DRDY;
WRITE_IDE_UCHAR(IDE_CMD_REG, IDE_IDDRIVE_CMD);
WAIT_IDE_BUSY;
WAIT_IDE_NOT_DRQ;
DEBUGMSG(ZONE_BOOTPROG, (TEXT("B9\r\n")));
if(IS_IDE_ERROR)
{
RETAILMSG(1, (TEXT("ERROR: Drive ID failed.\r\n")));
return(-1);
}
DEBUGMSG(ZONE_BOOTPROG, (TEXT("B10\r\n")));
// Read id info from IDE sector buffer
for(cnt = 0 ; cnt < (sizeof(drv_id_hdr) / sizeof(USHORT)) ; cnt++)
*((USHORT *)(&hdr) + cnt) = READ_IDE_USHORT(IDE_DATA_REG);
// Read the remainder of the sector buffer and toss away...
//
while(READ_IDE_UCHAR(IDE_STAT_REG) & IDE_STATUS_DRQ)
{
READ_IDE_USHORT(IDE_DATA_REG);
}
// Save away P-CHS conversion information for the drive.
g_drvparms.phy_cyls = hdr.lcyls;
g_drvparms.phy_heads = hdr.lheads;
g_drvparms.phy_sectspertrk = hdr.lsctptrk;
DEBUGMSG(ZONE_BOOTPROG, (TEXT("B11\r\n")));
// In theory, only LBA drives should set the total number of
// user-addressable sectors in the IDE ID packet. If we find a non-zero
// value, assume we have a drive that wants to talk LBA else use CHS.
//
//if (hdr.ttladdrscts)
if (1) // Assume LBA mode...
{
g_bLBAMode = TRUE;
DEBUGMSG(ZONE_INFO, (TEXT("LBA Mode (C:H:S = %d:%d:%d addressable sectors = %d).\r\n"), g_drvparms.phy_cyls, g_drvparms.phy_heads, g_drvparms.phy_sectspertrk, hdr.ttladdrscts));
}
else
{
g_bLBAMode = FALSE;
DEBUGMSG(ZONE_INFO, (TEXT("CHS Mode (C:H:S = %d:%d:%d).\r\n"), g_drvparms.phy_cyls, g_drvparms.phy_heads, g_drvparms.phy_sectspertrk));
}
RETAILMSG(1, (TEXT("Loading image from hard drive...\r\n")));
return(0);
}
int lba_to_pchs(ULONG lba,
USHORT *pc,
UCHAR *ph,
UCHAR *ps)
{
USHORT temp = 0;
// Make sure we know the drive geometry
if (g_drvparms.phy_cyls == 0 ||
g_drvparms.phy_heads == 0 ||
g_drvparms.phy_sectspertrk == 0)
return(-1);
if (pc == NULL || ph == NULL || ps == NULL)
return(-1);
// Do the math...
*pc = (USHORT)(lba / (g_drvparms.phy_heads * g_drvparms.phy_sectspertrk));
temp = (USHORT)(lba % (g_drvparms.phy_heads * g_drvparms.phy_sectspertrk));
*ph = (UCHAR)(temp / g_drvparms.phy_sectspertrk);
*ps = (UCHAR)(temp % g_drvparms.phy_sectspertrk) + 1;
return(0);
}
int read_sector(ULONG lba, unsigned char *pbuf)
{
USHORT c = 0;
UCHAR h = 0;
UCHAR s = 0;
USHORT i = 0;
UCHAR *a = NULL;
if (!pbuf)
return(-1);
// Convert LBA address to P-CHS for IDE controller
if (!g_bLBAMode)
{
if (lba_to_pchs(lba, &c, &h, &s))
return(-1);
DEBUGMSG(ZONE_INFO, (TEXT("INFO: Reading sector (P-CHS = %d:%d:%d).\r\n"), c, h, s));
}
else
DEBUGMSG(ZONE_INFO, (TEXT("INFO: Reading sector (LBA = 0x%x).\r\n"), lba));
// Program the IDE controller
WAIT_IDE_BUSY;
WRITE_IDE_UCHAR(IDE_SECTCNT_REG, 1);
if (!g_bLBAMode)
{
// CHS access...
//
WRITE_IDE_UCHAR(IDE_CYLL_REG, (UCHAR)(c & 0x00ff));
WRITE_IDE_UCHAR(IDE_CYLH_REG, (UCHAR)((c & 0xff00) >> 8));
// TODO - future drive num compensate.
WRITE_IDE_UCHAR(IDE_DRVHD_REG, (UCHAR)(h | IDE_HEAD_DRIVE_1));
WRITE_IDE_UCHAR(IDE_SECTNUM_REG, (UCHAR)s);
}
else
{
// LBA access...
//
WRITE_IDE_UCHAR(IDE_SECTNUM_REG, (UCHAR)(lba & 0xff));
WRITE_IDE_UCHAR(IDE_CYLL_REG, (UCHAR)((lba >> 8) & 0xff));
WRITE_IDE_UCHAR(IDE_CYLH_REG, (UCHAR)((lba >> 16) & 0xff));
// TODO - future drive num compensate.
WRITE_IDE_UCHAR(IDE_DRVHD_REG, (UCHAR)(((lba >> 24) & 0xff) | IDE_HEAD_DRIVE_1 | IDE_HEAD_LBA_MODE));
}
//
// Make sure interrupt enable bit is off (we'll poll)
//
//_outp(0x3f6, 0x0a);
WRITE_IDE_UCHAR(IDE_ALT_CTRL_REG, 0xA0);
WAIT_IDE_NOT_DRDY;
WRITE_IDE_UCHAR(IDE_CMD_REG, IDE_RDSECT_CMD);
WAIT_IDE_BUSY;
if (IS_IDE_ERROR)
{
RETAILMSG(1, (TEXT("ERROR: Sector read failed.\r\n")));
return(-1);
}
WAIT_IDE_NOT_DRQ;
// Copy sector buffer contents to callers buffer
for(i=0 ; i < (SECTOR_SIZE / sizeof(USHORT)) ; i++)
*((USHORT *)pbuf + i) = (USHORT)(READ_IDE_USHORT(IDE_DATA_REG));
// Increment total number of sectors and update status bar
if (g_bstartcounting)
{
++g_sectorsread;
//update_statusbar(&g_statbar, g_sectorsread);
}
return(0);
}
int init_ide(void)
{
// Get drive geometry info - needed for LBA -> P-CHS convertion
if (id_drive())
return(-1);
return(0);
}
// TODO: Resolve with OEMHDDPreDownload.
int load_image_ide(unsigned char *pname, ULONG *pimgloc)
{
int stat=0;
IMGHDR imghdr;
RECHDR rechdr;
ULONG cnt = 0;
DEBUGMSG(ZONE_BOOTPROG, (TEXT("B5\r\n")));
//
g_bstartcounting = 0;
g_sectorsread = 0;
// Initialize IDE
if (init_ide())
{
RETAILMSG(1, (TEXT("ERROR: IDE device initialization failed.\r\n")));
return(-1);
}
// Initialize FAT structs
if (init_fat())
{
RETAILMSG(1, (TEXT("ERROR: FAT initialization failed.\r\n")));
return(-1);
}
// Open image (finds starting LBA and size - inits structs for later ops)
// Only read is supported
if (file_open(pname))
{
RETAILMSG(1, (TEXT("ERROR: File open failed (%s)\r\n"), pname));
return(-1);
}
// Display status bar
//create_statusbar(&g_statbar, 0, (g_fileinfo.fsize / SECTOR_SIZE) - 1);
g_bstartcounting = 1;
// Get image header
stat = file_read((unsigned char *)&imghdr, sizeof(IMGHDR));
if (stat == FAT_EOF)
{
RETAILMSG(1, (TEXT("ERROR: EOF reading image header.\r\n")));
return(-1);
}
else if (stat)
{
RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
return(-1);
}
// Determine jump address
*pimgloc = imghdr.imgaddr;
// Display image header
DEBUGMSG(ZONE_INFO, (TEXT("Image Header:\r\n")));
DEBUGMSG(ZONE_INFO, (TEXT("-------------------------------------------\r\n")));
DEBUGMSG(ZONE_INFO, (TEXT("Sync Bytes = '%c%c%c%c%c%c'\r\n"), imghdr.syncbytes[0], imghdr.syncbytes[1], imghdr.syncbytes[2], imghdr.syncbytes[3], imghdr.syncbytes[4], imghdr.syncbytes[5]));
DEBUGMSG(ZONE_INFO, (TEXT("Image Address = 0x%x\r\n"), imghdr.imgaddr));
DEBUGMSG(ZONE_INFO, (TEXT("Image Length = 0x%x\r\n"), imghdr.imglen));
do
{
// Get record header
stat = file_read((unsigned char *)&rechdr, sizeof(RECHDR));
if (stat == FAT_EOF)
{
RETAILMSG(1, (TEXT("ERROR: EOF reading record header.\r\n")));
return(-1);
}
else if (stat)
{
RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
return(-1);
}
// Display Record Header
DEBUGMSG(ZONE_INFO, (TEXT("Record Header:\r\n")));
DEBUGMSG(ZONE_INFO, (TEXT("------------------------------------------\r\n")));
DEBUGMSG(ZONE_INFO, (TEXT("Record Address = 0x%x\r\n"), rechdr.recaddr));
DEBUGMSG(ZONE_INFO, (TEXT("Record Length = 0x%x\r\n"), rechdr.reclen));
DEBUGMSG(ZONE_INFO, (TEXT("Record CheckSum = 0x%x\r\n"), rechdr.recchksum));
// Last Header
if (rechdr.recaddr == 0 && rechdr.recchksum == 0)
break;
stat = file_read((unsigned char *)rechdr.recaddr, rechdr.reclen);
if (stat)
{
if (stat == EOF)
RETAILMSG(1, (TEXT("ERROR: EOF reading data.\r\n")));
else
RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
return(-1);
}
}
while(1);
// Close file
file_close();
return(0);
}
BOOL OEMHDDPlatformInit(VOID)
{
// For now, the RTL8139 product NIC driver requires an ILR in the PCI
// config space header otherwise it isn't able to get interrupts...
//
//InitNIC();
return(TRUE);
}
DWORD OEMHDDPreDownload(VOID)
{
UCHAR pName[] = KIMAGE_NAME;
//
g_bstartcounting = 0;
g_sectorsread = 0;
RETAILMSG(1, (TEXT("Initializing IDE drive (may take a second)...\r\n")));
//
// Set the IDE pcmcia cards attribute space to use memory and reset the PCMCIA card.
//
//*CF_CONFIG = CONFIG_LEVIRQ | CONFIG_SRESET;
*CF_CONFIG = CONFIG_LEVIRQ | 1;
// Initialize IDE
if (init_ide())
{
RETAILMSG(1, (TEXT("ERROR: IDE device initialization failed.\r\n")));
return(-1);
}
// Initialize FAT structs
if (init_fat())
{
RETAILMSG(1, (TEXT("ERROR: FAT initialization failed.\r\n")));
return(-1);
}
// Open image (finds starting LBA and size - inits structs for later ops)
// Only read is supported
if (file_open(pName))
{
RETAILMSG(1, (TEXT("ERROR: File open failed (%s).\r\n"), pName));
return(-1);
}
// Display status bar
//create_statusbar(&g_statbar, 0, (g_fileinfo.fsize / SECTOR_SIZE) - 1);
g_bstartcounting = 1;
return(BL_DOWNLOAD);
}
BOOL OEMHDDReadData(DWORD cbData, LPBYTE pbData)
{
int stat=0;
stat = file_read((unsigned char *)pbData, cbData);
if (stat == FAT_EOF)
{
RETAILMSG(1, (TEXT("ERROR: EOF reading record header.\r\n")));
return(FALSE);
}
else if (stat)
{
RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
return(FALSE);
}
return(TRUE);
}
#if 0
VOID OEMHDDLaunch(DWORD dwImageStart,
DWORD dwImageLength,
DWORD dwLaunchAddr,
const ROMHDR *pRomHdr)
{
((PFN_LAUNCH)(dwLaunchAddr))();
// Should never be reached.
SpinForever();
}
#endif // 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -