/*++ Copyright (c) 1992 Microsoft Corporation Module Name: dnboot.c Abstract: Routines for booting to NT text-mode setup. Author: Ted Miller (tedm) 2-April-1992 Revision History: --*/ #include "winnt.h" #include #include #include #include #include #include #include #include #if NEC_98 #include #include extern USHORT FirstFD; // 1'st Floppy Drive No #endif // NEC_98 // // This header file contains an array of 512 bytes // representing the NT FAT boot code, in a variable // of type unsigned char[] called FatBootCode. // #define _FAT32 #if NEC_98 #include #ifdef _FAT32 #include #endif #else #include #ifdef _FAT32 #include #endif #endif // NEC_98 #if NEC_98 #define FLOPPY_CAPACITY_525 1250304L #else // NEC_98 #define FLOPPY_CAPACITY_525 1213952L #endif // NEC_98 #define FLOPPY_CAPACITY_35 1457664L #ifdef ALLOW_525 #define FLOPPY_CAPACITY FLOPPY_CAPACITY_525 #else #define FLOPPY_CAPACITY FLOPPY_CAPACITY_35 #endif #define SECTOR_SIZE 512 // // Old int13 vector. See Int13Hook(), below. // void (_interrupt _far *OldInt13Vector)(); #if NEC_98 extern USHORT Cylinders; // For Dos 3.x format extern UCHAR TargetDA_UA; #endif // NEC_98 #pragma pack(1) // // Define bpb structure. // typedef struct _MY_BPB { USHORT BytesPerSector; UCHAR SectorsPerCluster; USHORT ReservedSectors; UCHAR FatCount; USHORT RootDirectoryEntries; USHORT SectorCountSmall; UCHAR MediaDescriptor; USHORT SectorsPerFat; USHORT SectorsPerTrack; USHORT HeadCount; } MY_BPB, *PMY_BPB; // // Define device params structure. // typedef struct _MY_DEVICE_PARAMS { UCHAR SpecialFunctions; UCHAR DeviceType; USHORT DeviceAttributes; USHORT CylinderCount; UCHAR MediaType; MY_BPB Bpb; ULONG HiddenSectors; ULONG SectorCountLarge; ULONG Padding[5]; // in case the struct grows in later dos versions! } MY_DEVICE_PARAMS, *PMY_DEVICE_PARAMS; // // Define read write block request for ioctl call. // typedef struct _MY_READWRITE_BLOCK { UCHAR SpecialFunctions; USHORT Head; USHORT Cylinder; USHORT FirstSector; USHORT SectorCount; VOID _far *Buffer; } MY_READWRITE_BLOCK, *PMY_READWRITE_BLOCK; #pragma pack() VOID DnInstallNtBoot( IN unsigned Drive // 0=A, etc ); unsigned DnpScanBootSector( IN PUCHAR BootSector, IN PUCHAR Pattern ); BOOLEAN DnpAreAllFilesPresent( IN CHAR DriveLetter, IN PCHAR FileList[] ); BOOLEAN DnpHasMZHeader( IN CHAR DriveLetter, IN PCHAR Filename ); BOOLEAN DnpInstallNtBootSector( IN unsigned Drive, // 0=A, etc. IN OUT PUCHAR BootSector, OUT PCHAR *PreviousOsText ); #if NEC_98 VOID RestoreBootcode(VOID); #endif // NEC_98 PCHAR MsDosFileList[] = { "?:\\MSDOS.SYS", "?:\\IO.SYS", NULL }; // // Some versions of PC-DOS have ibmio.com, others have ibmbio.com. // //PCHAR PcDosFileList[] = { "?:\\IBMDOS.COM", "?:\\IBMIO.COM", NULL }; #if NEC_98 #else // NEC_98 PCHAR PcDosFileList[] = { "?:\\IBMDOS.COM", NULL }; #endif PCHAR Os2FileList[] = { "?:\\OS2LDR", "?:\\OS2KRNL", NULL }; void _interrupt _far Int13Hook( unsigned _es, unsigned _ds, unsigned _di, unsigned _si, unsigned _bp, unsigned _sp, unsigned _bx, unsigned _dx, unsigned _cx, unsigned _ax, unsigned _ip, unsigned _cs, unsigned _flags ) /*++ Routine Description: We have encountered machines which cannot seem to create the floppies successfully. The user sees strange error messages about how the disk is not blank, etc even when the disk should be perfectly acceptable. To compensate for machines with broken change lines, we will hook int13 to force a disk change error on the very next int13 call after the user has inserted a new disk. The logic is simple: when we first start to make the boot floppies, we save away the int13 vector. Then right after the user presses return at a disk prompt (ie, when he confirms the presence of a new floppy in the drive), which is right before we do a getbpb call, we set a new int13 vector. The int13 hook simply unhooks itself and returns the disk change error. This should force dos to recognize the new disk at the proper times. Arguments: Registers pushed on stack as per spec of _interrupt-type functions. Return Value: None. We modify the ax and flags registers return values. --*/ { // // Unhook ourselves. // #if NEC_98 _dos_setvect(0x1b,OldInt13Vector); #else // NEC_98 _dos_setvect(0x13,OldInt13Vector); #endif // NEC_98 // // Force disk changed error. // _asm { mov _ax,0x600 or word ptr _flags,1 } } VOID DnpFlushBuffers( IN BOOLEAN TellUser ) /*++ Routine Description: Flush disk buffers. Arguments: TellUser - if TRUE, we clear the screen and put up a message telling the user that we are flushing files. Otherwise this routine doesn't touch the screen. Return Value: None. --*/ { if(TellUser) { DnClearClientArea(); DnWriteStatusText(DntFlushingData); } _asm { pusha mov ah,0xd int 21h popa } } VOID DnToNtSetup( VOID ) /*++ Routine Description: Launch NT text-mode setup. Make sure the boot floppy we created is in the drive and reboot the machine. Arguments: None. Return Value: None. Does not return. --*/ { ULONG ValidKey[2]; DnpFlushBuffers(TRUE); // // Make sure the setup boot floppy we created is in the drive // if necessary. // if(!DngUnattended) { DnClearClientArea(); if(DngWindows) { DnDisplayScreen( DngFloppyless ? &DnsAboutToExitX : (DngServer ? &DnsAboutToExitS : &DnsAboutToExitW) ); } else { DnDisplayScreen( DngFloppyless ? &DnsAboutToRebootX : (DngServer ? &DnsAboutToRebootS : &DnsAboutToRebootW) ); } DnWriteStatusText(DntEnterEqualsContinue); ValidKey[0] = ASCI_CR; ValidKey[1] = 0; DnGetValidKey(ValidKey); } // // Reboot the machine unless we are being run on Windows. // In that case, there should be a wrapper program that will shut down // the system using the Windows API -- our attempt to shut down using the // usual method will fail. // if(!DngWindows) { DnaReboot(); } } BOOLEAN DnIndicateWinnt( IN PCHAR Directory ) { PCHAR WinntData = WINNT_DATA_A; PCHAR WinntAccess = WINNT_ACCESSIBILITY_A; PCHAR WinntMsdos = WINNT_D_MSDOS_A; PCHAR WinntSif = WINNT_SIF_FILE_A; PCHAR WinntFloppy = WINNT_D_FLOPPY_A; PCHAR WinntUnattended = WINNT_UNATTENDED_A; PCHAR WinntOne = WINNT_A_ONE; PCHAR WinntZero = WINNT_A_ZERO; PCHAR WinntUpgrade = WINNT_U_NTUPGRADE; PCHAR WinntYes = WINNT_A_YES; PVOID InfHandle; PVOID UnattendHandle; PCHAR FileName; PCHAR p; PCHAR OptionalDirString; unsigned OptionalDirLength = 0; unsigned u,l; FILE *f; int Status; PCHAR SectionName; unsigned LineNumber; CHAR ServerAndShare[128]; BOOLEAN AccessibleSetup = FALSE; CHAR AccessibleScriptFile[] = "setupacc.txt"; // // Allocate a new INF file buffer // InfHandle = DnNewSetupTextFile(); if (InfHandle == NULL) { return (FALSE); } // // Build the default file name // FileName = MALLOC(strlen(Directory)+strlen(WinntSif)+2,TRUE); if(FileName == NULL) { DnFreeINFBuffer( InfHandle ); return FALSE; } // // Display to the user what we are doing // DnWriteStatusText(DntPreparingData); // // Build the name of the file we wish to save the INF file as // strcpy(FileName,Directory); strcat(FileName,"\\"); strcat(FileName,WinntSif); // // Handle Accessibility utilities // if(DngMagnifier) { DnAddLineToSection( InfHandle, WinntAccess, WINNT_D_ACC_MAGNIFIER, &WinntOne, 1); AccessibleSetup = TRUE; } if(DngTalker) { DnAddLineToSection( InfHandle, WinntAccess, WINNT_D_ACC_READER, &WinntOne, 1); AccessibleSetup = TRUE; } if(DngKeyboard) { DnAddLineToSection( InfHandle, WinntAccess, WINNT_D_ACC_KEYBOARD, &WinntOne, 1); AccessibleSetup = TRUE; } if(AccessibleSetup && !DngUnattended) { DngUnattended = TRUE; DngScriptFile = MALLOC(strlen(DngSourceRootPath) + strlen(AccessibleScriptFile) + 2, TRUE); if(DngScriptFile == NULL) { DnFatalError(&DnsOutOfMemory); } strcpy(DngScriptFile,DngSourceRootPath); strcat(DngScriptFile,"\\"); strcat(DngScriptFile,AccessibleScriptFile); } // // Append script file if necessary. // Do this processing first because we want to be able to // override anything that the user sets in the unattend file // that the user has no business setting // if(DngUnattended) { if(DngScriptFile) { // // First open the script file as a dos file // f = fopen(DngScriptFile,"rt"); if(f == NULL) { // // fatal error. // DnFatalError(&DnsOpenReadScript); } // // Now open it as a INF file // LineNumber = 0; Status = DnInitINFBuffer (f, &UnattendHandle, &LineNumber); fclose(f); if(Status == ENOMEM) { DnFatalError(&DnsOutOfMemory); } else if(Status) { DnFatalError(&DnsParseScriptFile, DngScriptFile, LineNumber); } // // Process all of the section names // for( SectionName = NULL; ((SectionName = DnGetSectionName( UnattendHandle )) != NULL); ) { // // We won't allow the data section or the [OemBootFiles] // to be copied // if ((strcmpi(WinntData,SectionName) != 0) && (strcmpi(WINNT_OEMBOOTFILES,SectionName) != 0) ) { // // Copy the sections from the Unattend INF // to the Main INF // DnCopySetupTextSection( UnattendHandle, InfHandle, SectionName); } FREE (SectionName); } // // We no longer need the unattend inf file at this point // DnFreeINFBuffer( UnattendHandle ); } if(!DngScriptFile) { // // No script. Put a dummy [Unattended] section in there. // DnAddLineToSection(InfHandle,WinntUnattended,"unused",&WinntZero,1); } } // // Add the default line to the inf // DnAddLineToSection( InfHandle, WinntData, WinntMsdos, &WinntOne, 1); // // Set the floppy flags // if(DngFloppyless) { DnAddLineToSection( InfHandle, WinntData, WinntFloppy, &WinntOne, 1); } else { DnAddLineToSection( InfHandle, WinntData, WinntFloppy, &WinntZero, 1); } // // Remember udf info // if(UniquenessId) { DnAddLineToSection( InfHandle, WinntData, WINNT_D_UNIQUENESS, &UniquenessId, 1); } // // Write info about original source. // // We only distinguish here between remote and CD-ROM. // If it doesn't appear to be a remote drive, either by // being UNC or a redirected local drive, then we assume // it's a CD-ROM drive (this behavior is intended to force // GUI Setup to locate a valid CD-ROM if one is available). // Because we have no idea what the drive letters will be // on NT, we always write A: in there. // #define DRIVE_REMOTE 4 #define DRIVE_CDROM 5 u = DRIVE_CDROM; if(DngOemPreInstall) { // // Preinstall case, force GUI Setup to locate a CD-ROM drive // and assume the I386 directory is on the root of the CD // (that's how we ship the retail CDs). // strcpy(ServerAndShare,"A:\\I386"); } else { if(DngSourceRootPath[0] == '\\') { // // UNC path. change drive type to remote and remember // the entire path. // u = DRIVE_REMOTE; strcpy(ServerAndShare,DngSourceRootPath); } else { // // Assume fully-qualified path starting with a drive letter. // if(DnIsDriveRemote((unsigned)DngSourceRootPath[0]+1-(unsigned)'A',ServerAndShare)) { // // It's a redirected network drive. // if(ServerAndShare[0]) { // // Change type to remote drive. ServerAndShare has the // \\server\share, to which we append the rest of the path, below. // u = DRIVE_REMOTE; } else { // // Strange case where we can't resolve the local drive letter // to its server and share. Leave as CD-ROM. // ServerAndShare[0] = 'A'; ServerAndShare[1] = ':'; ServerAndShare[2] = 0; } strcat(ServerAndShare,DngSourceRootPath+2); } else { // // Not a network drive. Assume CD-ROM. // strcpy(ServerAndShare,DngSourceRootPath); ServerAndShare[0] = 'A'; } } } p = ServerAndShare; DnAddLineToSection(InfHandle,WinntData,WINNT_D_ORI_SRCPATH,&p,1); sprintf(p,"%u",u); DnAddLineToSection(InfHandle,WinntData,WINNT_D_ORI_SRCTYPE,&p,1); if(CmdToExecuteAtEndOfGui) { DnAddLineToSection(InfHandle,WINNT_SETUPPARAMS,WINNT_S_USEREXECUTE,&CmdToExecuteAtEndOfGui,1); } if(OptionalDirCount) { // // If an optional dir string is present then we want to generate // and entry in the sif file that contains a line with the dir // string in the form of dir1*dir2*...*dirn // OptionalDirString = NULL; for(u=0; u