Added FAT image access and DOS booter functionality
Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1757
This commit is contained in:
parent
57a7795ae0
commit
d0e2bfa15f
7 changed files with 2024 additions and 48 deletions
|
@ -21,60 +21,425 @@
|
|||
#include "bios.h"
|
||||
#include "regs.h"
|
||||
#include "mem.h"
|
||||
#include "keyboard.h"
|
||||
#include "dos_inc.h" /* for Drives[] */
|
||||
|
||||
static Bitu call_int13;
|
||||
static BIOS_Disk * Floppys[2];
|
||||
static BIOS_Disk * Harddisks[BIOS_MAX_DISK];
|
||||
#define MAX_SWAPPABLE_DISKS 20
|
||||
|
||||
diskGeo DiskGeometryList[] = {
|
||||
{160, 8, 1, 40, 0},
|
||||
{180, 9, 1, 40, 0},
|
||||
{320, 8, 2, 40, 1},
|
||||
{360, 9, 2, 40, 1},
|
||||
{720, 9, 2, 80, 3},
|
||||
{1200, 15, 2, 80, 2},
|
||||
{1440, 18, 2, 80, 4},
|
||||
{2880, 36, 2, 80, 6},
|
||||
{0, 0, 0 , 0},
|
||||
};
|
||||
|
||||
Bitu call_int13;
|
||||
Bitu diskparm0, diskparm1;
|
||||
static Bit8u last_status;
|
||||
static Bit8u last_drive;
|
||||
Bit16u imgDTASeg;
|
||||
RealPt imgDTAPtr;
|
||||
DOS_DTA *imgDTA;
|
||||
bool killRead;
|
||||
|
||||
/* 2 floppys and 2 harddrives, max */
|
||||
imageDisk *imageDiskList[4];
|
||||
imageDisk *diskSwap[MAX_SWAPPABLE_DISKS];
|
||||
Bits swapPosition;
|
||||
|
||||
void updateDPT(void) {
|
||||
Bit32u tmpheads, tmpcyl, tmpsect, tmpsize;
|
||||
if(imageDiskList[2] != NULL) {
|
||||
imageDiskList[2]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize);
|
||||
real_writew(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0)),tmpcyl);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+2,tmpheads);
|
||||
real_writew(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0x3,0);
|
||||
real_writew(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0x5,-1);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0x7,0);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0x8,(0xc0 | (((imageDiskList[2]->heads) > 8) << 3)));
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0x9,0);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0xa,0);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0xb,0);
|
||||
real_writew(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0xc,tmpcyl);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+0xe,tmpsect);
|
||||
|
||||
|
||||
|
||||
}
|
||||
if(imageDiskList[3] != NULL) {
|
||||
imageDiskList[3]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize);
|
||||
real_writew(RealSeg(CALLBACK_RealPointer(diskparm1)),RealOff(CALLBACK_RealPointer(diskparm1)),tmpcyl);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm1)),RealOff(CALLBACK_RealPointer(diskparm1))+2,tmpheads);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm1)),RealOff(CALLBACK_RealPointer(diskparm1))+0xe,tmpsect);
|
||||
}
|
||||
|
||||
|
||||
static Bitu INT13_SmallHandler(void) {
|
||||
switch (reg_ah) {
|
||||
}
|
||||
|
||||
void swapInDisks(void) {
|
||||
bool allNull = true;
|
||||
Bits diskcount = 0;
|
||||
Bits swapPos = swapPosition;
|
||||
int i;
|
||||
|
||||
/* Check to make sure there's atleast one setup image */
|
||||
for(i=0;i<MAX_SWAPPABLE_DISKS;i++) {
|
||||
if(diskSwap[i]!=NULL) {
|
||||
allNull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No disks setup... fail */
|
||||
if (allNull) return;
|
||||
|
||||
/* If only one disk is loaded, this loop will load the same disk in dive A and drive B */
|
||||
while(diskcount<2) {
|
||||
if(diskSwap[swapPos] != NULL) {
|
||||
LOG_MSG("Loaded disk %d from swaplist position %d - \"%s\"", diskcount, swapPos, diskSwap[swapPos]->diskname);
|
||||
imageDiskList[diskcount] = diskSwap[swapPos];
|
||||
diskcount++;
|
||||
}
|
||||
swapPos++;
|
||||
if(swapPos>=MAX_SWAPPABLE_DISKS) swapPos=0;
|
||||
}
|
||||
}
|
||||
|
||||
static void swapInNextDisk(void) {
|
||||
swapPosition++;
|
||||
if(diskSwap[swapPosition] == NULL) swapPosition = 0;
|
||||
swapInDisks();
|
||||
}
|
||||
|
||||
|
||||
Bit8u imageDisk::Read_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data) {
|
||||
Bit32u sectnum;
|
||||
|
||||
sectnum = ( (cylinder * heads + head) * sectors ) + sector - 1L;
|
||||
|
||||
return Read_AbsoluteSector(sectnum, data);
|
||||
}
|
||||
|
||||
Bit8u imageDisk::Read_AbsoluteSector(Bit32u sectnum, void * data) {
|
||||
Bit32u bytenum;
|
||||
|
||||
bytenum = sectnum * sector_size;
|
||||
|
||||
fseek(diskimg,bytenum,SEEK_SET);
|
||||
fread(data, 1, sector_size, diskimg);
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
Bit8u imageDisk::Write_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data) {
|
||||
Bit32u sectnum;
|
||||
|
||||
sectnum = ( (cylinder * heads + head) * sectors ) + sector - 1L;
|
||||
|
||||
return Write_AbsoluteSector(sectnum, data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Bit8u imageDisk::Write_AbsoluteSector(Bit32u sectnum, void *data) {
|
||||
Bit32u bytenum;
|
||||
|
||||
bytenum = sectnum * sector_size;
|
||||
|
||||
//LOG_MSG("Writing sectors to %ld at bytenum %d", sectnum, bytenum);
|
||||
|
||||
fseek(diskimg,bytenum,SEEK_SET);
|
||||
fwrite(data, sector_size, 1, diskimg);
|
||||
|
||||
return 0x00;
|
||||
|
||||
}
|
||||
|
||||
imageDisk::imageDisk(FILE *imgFile, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk) {
|
||||
heads = 0;
|
||||
cylinders = 0;
|
||||
sectors = 0;
|
||||
sector_size = 512;
|
||||
diskimg = imgFile;
|
||||
|
||||
memset(diskname,0,512);
|
||||
if(strlen((const char *)imgName) > 511) {
|
||||
memcpy(diskname, imgName, 511);
|
||||
} else {
|
||||
strcpy((char *)diskname, (const char *)imgName);
|
||||
}
|
||||
|
||||
active = false;
|
||||
hardDrive = isHardDisk;
|
||||
if(!isHardDisk) {
|
||||
Bitu i=0;
|
||||
bool founddisk = false;
|
||||
while (DiskGeometryList[i].ksize!=0x0) {
|
||||
if (DiskGeometryList[i].ksize==imgSizeK) {
|
||||
founddisk = true;
|
||||
active = true;
|
||||
floppytype = i;
|
||||
heads = DiskGeometryList[i].headscyl;
|
||||
cylinders = DiskGeometryList[i].cylcount;
|
||||
sectors = DiskGeometryList[i].secttrack;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(!founddisk) {
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imageDisk::Set_Geometry(Bit32u setHeads, Bit32u setCyl, Bit32u setSect, Bit32u setSectSize) {
|
||||
heads = setHeads;
|
||||
cylinders = setCyl;
|
||||
sectors = setSect;
|
||||
sector_size = setSectSize;
|
||||
active = true;
|
||||
}
|
||||
|
||||
void imageDisk::Get_Geometry(Bit32u * getHeads, Bit32u *getCyl, Bit32u *getSect, Bit32u *getSectSize) {
|
||||
*getHeads = heads;
|
||||
*getCyl = cylinders;
|
||||
*getSect = sectors;
|
||||
*getSectSize = sector_size;
|
||||
}
|
||||
|
||||
Bit8u imageDisk::GetBiosType(void) {
|
||||
if(!hardDrive) {
|
||||
return DiskGeometryList[floppytype].biosval;
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
Bit32u imageDisk::getSectSize(void) {
|
||||
return sector_size;
|
||||
}
|
||||
|
||||
static Bitu GetDosDriveNumber(Bitu biosNum) {
|
||||
switch(biosNum) {
|
||||
case 0x0:
|
||||
reg_ah=0x00;
|
||||
return 0x0;
|
||||
case 0x1:
|
||||
return 0x1;
|
||||
case 0x80:
|
||||
return 0x2;
|
||||
case 0x81:
|
||||
return 0x3;
|
||||
case 0x82:
|
||||
return 0x4;
|
||||
case 0x83:
|
||||
return 0x5;
|
||||
default:
|
||||
return 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
static bool driveInactive(Bitu driveNum) {
|
||||
if(driveNum>=(2 + MAX_HDD_IMAGES)) {
|
||||
LOG_MSG("Disk %d non-existant", driveNum);
|
||||
last_status = 0x01;
|
||||
CALLBACK_SCF(true);
|
||||
return true;
|
||||
}
|
||||
if(imageDiskList[driveNum] == NULL) {
|
||||
LOG_MSG("Disk %d not active", driveNum);
|
||||
last_status = 0x01;
|
||||
CALLBACK_SCF(true);
|
||||
return true;
|
||||
}
|
||||
if(!imageDiskList[driveNum]->active) {
|
||||
LOG_MSG("Disk %d not active", driveNum);
|
||||
last_status = 0x01;
|
||||
CALLBACK_SCF(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static Bitu INT13_DiskHandler(void) {
|
||||
Bit16u segat, bufptr;
|
||||
Bit8u sectbuf[512];
|
||||
Bitu drivenum;
|
||||
Bits readcnt;
|
||||
int i,t;
|
||||
last_drive = reg_dl;
|
||||
drivenum = GetDosDriveNumber(reg_dl);
|
||||
//drivenum = 0;
|
||||
//LOG_MSG("INT13: Function %x called on drive %x (dos drive %d)", reg_ah, reg_dl, drivenum);
|
||||
switch(reg_ah) {
|
||||
case 0x0: /* Reset disk */
|
||||
if(driveInactive(drivenum)) return CBRET_NONE;
|
||||
last_status = 0x00;
|
||||
CALLBACK_SCF(false);
|
||||
LOG(LOG_BIOS,LOG_NORMAL)("reset disk return succesfull");
|
||||
break;
|
||||
case 0x02: /* Read Disk Sectors */
|
||||
LOG(LOG_BIOS,LOG_NORMAL)("INT13:02:Read Disk Sectors not supported failing");
|
||||
reg_ah=0x80;
|
||||
case 0x1: /* Get status of last operation */
|
||||
|
||||
if(last_status != 0x00) {
|
||||
reg_ah = last_status;
|
||||
CALLBACK_SCF(true);
|
||||
} else {
|
||||
reg_ah = 0x00;
|
||||
CALLBACK_SCF(false);
|
||||
}
|
||||
break;
|
||||
case 0x04:
|
||||
if(Drives[reg_dl]!=NULL) {
|
||||
reg_ah=0;
|
||||
case 0x2: /* Read sectors */
|
||||
if(driveInactive(drivenum)) {
|
||||
reg_ah = 0xff;
|
||||
CALLBACK_SCF(true);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
segat = SegValue(es);
|
||||
bufptr = reg_bx;
|
||||
for(i=0;i<reg_al;i++) {
|
||||
last_status = imageDiskList[drivenum]->Read_Sector((Bit32u)reg_dh, (Bit32u)(reg_ch | ((reg_cl & 0xc0)<< 2)), (Bit32u)((reg_cl & 63)+i), sectbuf);
|
||||
if((last_status != 0x00) || (killRead)) {
|
||||
LOG_MSG("Error in disk read");
|
||||
killRead = false;
|
||||
reg_ah = 0x04;
|
||||
CALLBACK_SCF(true);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
for(t=0;t<512;t++) {
|
||||
real_writeb(segat,bufptr,sectbuf[t]);
|
||||
bufptr++;
|
||||
}
|
||||
}
|
||||
reg_ah = 0x00;
|
||||
CALLBACK_SCF(false);
|
||||
}
|
||||
else{
|
||||
reg_ah=0x80;
|
||||
CALLBACK_SCF(true);
|
||||
}
|
||||
LOG(LOG_BIOS,LOG_NORMAL)("INT 13:04 Verify sector used on %d, with result %d",reg_dl,reg_ah);
|
||||
break;
|
||||
|
||||
case 0x08: /* Get Drive Parameters */
|
||||
LOG(LOG_BIOS,LOG_NORMAL)("INT13:08:Get Drive parameters not supported failing");
|
||||
reg_ah=0xff;
|
||||
CALLBACK_SCF(true);
|
||||
break;
|
||||
case 0xff:
|
||||
case 0x3: /* Write sectors */
|
||||
|
||||
if(driveInactive(drivenum)) {
|
||||
reg_ah = 0xff;
|
||||
CALLBACK_SCF(true);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
|
||||
bufptr = reg_bx;
|
||||
for(i=0;i<reg_al;i++) {
|
||||
for(t=0;t<imageDiskList[drivenum]->getSectSize();t++) {
|
||||
sectbuf[t] = real_readb(SegValue(es),bufptr);
|
||||
bufptr++;
|
||||
}
|
||||
|
||||
last_status = imageDiskList[drivenum]->Write_Sector((Bit32u)reg_dh, (Bit32u)(reg_ch | ((reg_cl & 0xc0) << 2)), (Bit32u)((reg_cl & 63) + i), §buf[0]);
|
||||
if(last_status != 0x00) {
|
||||
CALLBACK_SCF(true);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
}
|
||||
CALLBACK_SCF(false);
|
||||
break;
|
||||
case 0x04: /* Verify sectors */
|
||||
if(driveInactive(drivenum)) return CBRET_NONE;
|
||||
|
||||
/* TODO: Finish coding this section */
|
||||
/*
|
||||
segat = SegValue(es);
|
||||
bufptr = reg_bx;
|
||||
for(i=0;i<reg_al;i++) {
|
||||
last_status = imageDiskList[drivenum]->Read_Sector((Bit32u)reg_dh, (Bit32u)(reg_ch | ((reg_cl & 0xc0)<< 2)), (Bit32u)((reg_cl & 63)+i), sectbuf);
|
||||
if(last_status != 0x00) {
|
||||
LOG_MSG("Error in disk read");
|
||||
CALLBACK_SCF(true);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
for(t=0;t<512;t++) {
|
||||
real_writeb(segat,bufptr,sectbuf[t]);
|
||||
bufptr++;
|
||||
}
|
||||
}*/
|
||||
reg_ah = 0x00;
|
||||
//reg_al = 0x10; /* CRC verify failed */
|
||||
reg_al = 0x00; /* CRC verify succeeded */
|
||||
CALLBACK_SCF(false);
|
||||
|
||||
break;
|
||||
case 0x08: /* Get drive parameters */
|
||||
if(driveInactive(drivenum)) {
|
||||
last_status = 0x07;
|
||||
reg_ah = last_status;
|
||||
CALLBACK_SCF(true);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
reg_ax = 0x00;
|
||||
reg_bl = imageDiskList[drivenum]->GetBiosType();
|
||||
Bit32u tmpheads, tmpcyl, tmpsect, tmpsize;
|
||||
imageDiskList[drivenum]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize);
|
||||
reg_ch = tmpcyl;
|
||||
reg_cl = tmpsect;
|
||||
reg_dh = tmpheads-1;
|
||||
last_status = 0x00;
|
||||
reg_dl = 0;
|
||||
if(imageDiskList[2] != NULL) reg_dl++;
|
||||
if(imageDiskList[3] != NULL) reg_dl++;
|
||||
CALLBACK_SCF(false);
|
||||
break;
|
||||
case 0x11: /* Recalibrate drive */
|
||||
reg_ah = 0x00;
|
||||
CALLBACK_SCF(false);
|
||||
break;
|
||||
case 0x17: /* Set disk type for format */
|
||||
/* Pirates! needs this to load */
|
||||
killRead = true;
|
||||
reg_ah = 0x00;
|
||||
CALLBACK_SCF(false);
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_BIOS,LOG_ERROR)("Illegal int 13h call %2X Fail it",reg_ah);
|
||||
LOG_MSG("INT13: Function %x called on drive %x (dos drive %d)", reg_ah, reg_dl, drivenum);
|
||||
reg_ah=0xff;
|
||||
CALLBACK_SCF(true);
|
||||
}
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
|
||||
void BIOS_SetupDisks(void) {
|
||||
/* TODO Start the time correctly */
|
||||
call_int13=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_int13,&INT13_SmallHandler,CB_IRET);
|
||||
//CALLBACK_Setup(call_int13,&INT13_SmallHandler,CB_IRET);
|
||||
CALLBACK_Setup(call_int13,&INT13_DiskHandler,CB_IRET);
|
||||
RealSetVec(0x13,CALLBACK_RealPointer(call_int13));
|
||||
/* Init the Disk Tables */
|
||||
last_status=0;
|
||||
int i;
|
||||
for(i=0;i<4;i++) {
|
||||
imageDiskList[i] = NULL;
|
||||
}
|
||||
|
||||
for(i=0;i<MAX_SWAPPABLE_DISKS;i++) {
|
||||
diskSwap[i] = NULL;
|
||||
}
|
||||
|
||||
diskparm0 = CALLBACK_Allocate();
|
||||
diskparm1 = CALLBACK_Allocate();
|
||||
swapPosition = 0;
|
||||
|
||||
RealSetVec(0x41,CALLBACK_RealPointer(diskparm0));
|
||||
RealSetVec(0x46,CALLBACK_RealPointer(diskparm1));
|
||||
|
||||
for(i=0;i<16;i++) {
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm0)),RealOff(CALLBACK_RealPointer(diskparm0))+i,0);
|
||||
real_writeb(RealSeg(CALLBACK_RealPointer(diskparm1)),RealOff(CALLBACK_RealPointer(diskparm1))+i,0);
|
||||
}
|
||||
|
||||
imgDTASeg = 0;
|
||||
|
||||
/* Setup the Bios Area */
|
||||
mem_writeb(BIOS_HARDDISK_COUNT,0);
|
||||
mem_writeb(BIOS_HARDDISK_COUNT,2);
|
||||
|
||||
KEYBOARD_AddEvent(KBD_f4,KBD_MOD_CTRL, swapInNextDisk);
|
||||
|
||||
killRead = false;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue