/*++ 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 // // This header file contains an array of 512 bytes // representing the NT FAT boot code, in a variable // of type unsigned char[] called FatBootCode. // #include #define FLOPPY_CAPACITY_525 1213952L #define FLOPPY_CAPACITY_35 1457664L #ifdef ALLOW_525 #define FLOPPY_CAPACITY FLOPPY_CAPACITY_525 #else #define FLOPPY_CAPACITY FLOPPY_CAPACITY_35 #endif // // Old int13 vector. See Int13Hook(), below. // void (_interrupt _far *OldInt13Vector)(void); #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 ); 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 }; PCHAR PcDosFileList[] = { "?:\\IBMDOS.COM", NULL }; 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. // _dos_setvect(0x13,OldInt13Vector); // // 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 forcibly 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 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; int f; int Status; PCHAR SectionName; unsigned LineNumber; CHAR ServerAndShare[128]; // // 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); // // 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 // if(_dos_open(DngScriptFile,O_RDONLY,&f)) { // // fatal error. // DnFatalError(&DnsOpenReadScript); } // // Now open it as a INF file // LineNumber = 0; Status = DnInitINFBuffer(f,&UnattendHandle, &LineNumber); if(Status == ENOMEM) { DnFatalError(&DnsOutOfMemory); } else if(Status) { DnFatalError(&DnsParseScriptFile, DngScriptFile, LineNumber); } // // We no longer need the file handle // _dos_close(f); // // 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); } } // // We no longer need the unattend inf file at this point // DnFreeINFBuffer( UnattendHandle ); } if (!DngScriptFile) { // // No script. Put a dummy [Unattended] section in there // so text setup will know it's unattended upgrade setup. // DnAddLineToSection( InfHandle, WinntUnattended, WinntUpgrade, &WinntYes, 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. // Canonicalize the source root path to facilitate this. // If the canonicalized path starts with \ then we assume // it's UNC. Otherwise it might be a redirected local drive // or an actual local drive. In the latter case we assume // CD-ROM. // // If we can't canonicalize for some reason. Don't save any info // in the setup parameter file in this case, which lets // GUI setup do the default. // if(DngSourceRootPath[0] == '\\') { u = 4; // DRIVE_REMOTE p = DngSourceRootPath; } else { if(DnIsDriveRemote((unsigned)DngSourceRootPath[0]+1-(unsigned)'A',ServerAndShare)) { if(ServerAndShare[0]) { u = 4; // DRIVE_REMOTE strcat(ServerAndShare,DngSourceRootPath+2); p = ServerAndShare; } else { // // Strange case where we can't resolve the local drive letter // to its server and share. Write no data in this case. // p = NULL; } } else { u = 5; // DRIVE_CDROM p = DngSourceRootPath; } } // // In the preinstall case ignore the above and force GUI setup // to look for a CD-ROM to use. // // This combination of values will do it. // if(DngOemPreInstall) { strcpy(ServerAndShare,"A:\\I386"); p = ServerAndShare; u = 5; // DRIVE_CDROM } if(p) { DnAddLineToSection(InfHandle,WinntData,WINNT_D_ORI_SRCPATH,&p,1); p = ServerAndShare; 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