/*++ Copyright (c) 1991 Microsoft Corporation Module Name: osloader.c Abstract: This module contains the code that implements the NT operating system loader. Author: David N. Cutler (davec) 10-May-1991 Revision History: --*/ #include "bldr.h" #include "haldtect.h" #include "parseini.h" #include "setupbat.h" #include "ctype.h" #include "stdio.h" #include "string.h" #include "msg.h" #include #if defined(REMOTE_BOOT) extern BOOLEAN NetFS_Cache; UCHAR szRemoteBootCfgFile[] = "RemoteBoot.cfg"; CHAR KernelFileName[8+1+3+1]="ntoskrnl.exe"; CHAR HalFileName[8+1+3+1]="hal.dll"; VOID BlWarnAboutFormat( IN BOOLEAN SecretValid, IN PUCHAR OsLoader ); ARC_STATUS BlCheckMachineReplacement ( IN PCHAR SystemDevice, IN ULONG SystemDeviceId, IN ULONGLONG NetRebootParameter, IN PUCHAR OsLoader ) /*++ Routine Description: This routine checks to see if a part of the machine has been replaced. Specifically, it checks if: - Hal is different. - Physical Disk is different. If it finds either case, then it creates at SETUP_LOADER_BLOCK and sets the flags to pass to the kernel. Note: NetFS_Cache is a boolean which is used to turn on/off client side caching in the loader. When set to FALSE, the cache is turned off. Arguments: SystemDevice - Character string of the ARC name of the system. SystemDeviceId - Handle to the server share where this machine account exists. NetRebootParameter - Any parameter that may have been passed during a soft reboot of the PC. OsLoader - TFTP path to osloader.exe Return Value: Success or not. Failure means to quit loading. --*/ { ARC_DISK_SIGNATURE Signature; ARC_STATUS Status; BOOLEAN NetBootRequiresFormat = FALSE; BOOLEAN NetBootClientCacheStale = FALSE; BOOLEAN NetBootDisconnected = FALSE; BOOLEAN SkipHalCheck; ULONG FileId; ULONG CacheBootSerialNumber; ULONG CacheDiskSignature; ULONG ServerBootSerialNumber; ULONG ServerDiskSignature; UCHAR NetBootHalName[MAX_HAL_NAME_LENGTH + 1]; PUCHAR NetBootDetectedHalName; UCHAR OutputBuffer[256]; UCHAR DiskName[80]; PUCHAR p; PUCHAR Guid; ULONG GuidLength; // // Detect which HAL we want to use. // NetBootDetectedHalName = SlDetectHal(); SkipHalCheck = (NetBootDetectedHalName == NULL); if (!NetworkBootRom) { NetBootDisconnected = TRUE; goto EndTesting; } strcpy(OutputBuffer, NetBootPath); strcat(OutputBuffer, szRemoteBootCfgFile); if (BlOpen(SystemDeviceId, OutputBuffer, ArcOpenReadOnly, &FileId) == ESUCCESS) { Status = BlReadAtOffset(FileId, 0, sizeof(ULONG), &CacheBootSerialNumber); BlClose(FileId); if (Status != ESUCCESS) { NetBootClientCacheStale = TRUE; NetBootRequiresFormat = TRUE; NetFS_Cache = FALSE; goto EndTesting; } NetFS_Cache = FALSE; if (BlOpen(SystemDeviceId, OutputBuffer, ArcOpenReadOnly, &FileId) == ESUCCESS) { // Get parameters from each file Status = BlReadAtOffset(FileId, 0, sizeof(ULONG), &ServerBootSerialNumber); if (Status != ESUCCESS) { NetBootClientCacheStale = TRUE; NetBootRequiresFormat = TRUE; BlClose(FileId); goto EndTesting; } Status = BlReadAtOffset(FileId, sizeof(ULONG), sizeof(ULONG), &ServerDiskSignature); if (Status != ESUCCESS) { NetBootClientCacheStale = TRUE; NetBootRequiresFormat = TRUE; BlClose(FileId); goto EndTesting; } Signature.ArcName = OutputBuffer; strcpy(DiskName, NetBootActivePartitionName); p = strstr(DiskName, "partition"); ASSERT( p != NULL ); *p = '\0'; if (!BlGetDiskSignature(DiskName, FALSE, &Signature )) { // Assume diskless PC BlClose(FileId); goto EndTesting; } CacheDiskSignature = Signature.Signature; if (CacheBootSerialNumber < ServerBootSerialNumber) { NetBootClientCacheStale = TRUE; } if (CacheDiskSignature != ServerDiskSignature) { NetBootClientCacheStale = TRUE; NetBootRequiresFormat = TRUE; BlClose(FileId); goto EndTesting; } Status = BlReadAtOffset(FileId, sizeof(ULONG) + sizeof(ULONG), sizeof(char) * (MAX_HAL_NAME_LENGTH+1), NetBootHalName ); if (Status != ESUCCESS) { NetBootClientCacheStale = TRUE; NetBootRequiresFormat = TRUE; BlClose(FileId); goto EndTesting; } GetGuid(&Guid, &GuidLength); if (!SkipHalCheck && strncmp(NetBootHalName, NetBootDetectedHalName, MAX_HAL_NAME_LENGTH)) { if (!NT_SUCCESS(NetCopyHalAndKernel(NetBootDetectedHalName, Guid, GuidLength))) { Status = EMFILE; goto CleanUp; } NetBootClientCacheStale = TRUE; } BlClose(FileId); } else { // Running disconnected. Assume everything is ok. NetBootDisconnected = TRUE; } if (!NetBootClientCacheStale) { NetFS_Cache = TRUE; } } else { NetFS_Cache = FALSE; NetBootClientCacheStale = TRUE; NetBootRequiresFormat = TRUE; } EndTesting: Status = ESUCCESS; if (NetBootRequiresFormat) { BlWarnAboutFormat((BOOLEAN)(NetRebootParameter == NET_REBOOT_SECRET_VALID), OsLoader); } BlLoaderBlock->SetupLoaderBlock->Flags |= SETUPBLK_FLAGS_IS_REMOTE_BOOT; if (NetBootClientCacheStale) { NetBootRepin = TRUE; } if ( NetBootDisconnected ) { BlLoaderBlock->SetupLoaderBlock->Flags |= SETUPBLK_FLAGS_DISCONNECTED; } if ( NetBootRequiresFormat ) { BlLoaderBlock->SetupLoaderBlock->Flags |= SETUPBLK_FLAGS_FORMAT_NEEDED; } memcpy(BlLoaderBlock->SetupLoaderBlock->NetBootHalName, NetBootDetectedHalName, sizeof(BlLoaderBlock->SetupLoaderBlock->NetBootHalName) ); BlLoaderBlock->SetupLoaderBlock->NetBootHalName[MAX_HAL_NAME_LENGTH] = '\0'; CleanUp: return Status; } VOID BlWarnAboutFormat( IN BOOLEAN SecretValid, IN PUCHAR OsLoader ) /*++ Routine Description: This routine provides the user-interface for warning the user that a new harddisk has been detected and will be formatted. Arguments: SecretValid - If TRUE, then return because there is no message for the user, otherwise display a message that the user must logon and the disk will be wiped out. OsLoader - Path for TFTP to the osloader.exe image. Return Value: None. --*/ { ULONG HeaderLines; ULONG TrailerLines; ULONG Count; UCHAR Key; PCHAR MenuHeader; PCHAR MenuTrailer; PCHAR Temp; ULONG DisplayLines; ULONG CurrentSelection = 0; UCHAR Buffer[16]; if (SecretValid) { // We don't present the user with a screen in this case because we have already forced // a logon and a rewrite of the secret. return; } else { MenuHeader = BlFindMessage(BL_FORCELOGON_HEADER); } MenuTrailer = BlFindMessage(BL_WARNFORMAT_TRAILER); sprintf(Buffer, "%s%s", ASCI_CSI_OUT, ";44;37m"); // White on Blue ArcWrite(BlConsoleOutDeviceId, Buffer, strlen(Buffer), &Count); BlClearScreen(); sprintf(Buffer, "%s%s", ASCI_CSI_OUT, ";37;44m"); // Blue on white ArcWrite(BlConsoleOutDeviceId, Buffer, strlen(Buffer), &Count); // // Count the number of lines in the header. // HeaderLines=BlCountLines(MenuHeader); // // Display the menu header. // ArcWrite(BlConsoleOutDeviceId, MenuHeader, strlen(MenuHeader), &Count); // // Count the number of lines in the trailer. // TrailerLines=BlCountLines(MenuTrailer); BlPositionCursor(1, ScreenHeight-TrailerLines); ArcWrite(BlConsoleOutDeviceId, MenuTrailer, strlen(MenuTrailer), &Count); // // Compute number of selections that can be displayed // DisplayLines = ScreenHeight-HeaderLines-TrailerLines-3; // // Start menu selection loop. // do { Temp = BlFindMessage(BL_WARNFORMAT_CONTINUE); if (Temp != NULL) { BlPositionCursor(5, HeaderLines+3); BlSetInverseMode(TRUE); ArcWrite(BlConsoleOutDeviceId, Temp, strlen(Temp), &Count); BlSetInverseMode(FALSE); } // // Loop waiting for keypress or time change. // do { if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) { BlPositionCursor(1,ScreenHeight); BlClearToEndOfLine(); ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &Count); break; } } while ( TRUE ); switch (Key) { case ASCI_CSI_IN: ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &Count); break; default: break; } } while ( (Key != ASCII_CR) && (Key != ASCII_LF) ); BlClearScreen(); if (!SecretValid) { while ( TRUE ) { NetSoftReboot( #if defined(_ALPHA_) #if defined(_AXP64_) "OSChooser\\axp64\\startrom.com", #else "OSChooser\\alpha\\startrom.com", #endif #endif #if defined(_MIPS_) "OSChooser\\mips\\startrom.com", #endif #if defined(_PPC_) "OSChooser\\ppc\\startrom.com", #endif #if defined(_IA64_) "OSChooser\\ia64\\startrom.com", #endif #if defined(_X86_) "OSChooser\\i386\\startrom.com", #endif NET_REBOOT_WRITE_SECRET_ONLY, OsLoader, NULL, // SIF file NULL, // user NULL, // domain NULL // password ); } } } #endif // defined(REMOTE_BOOT) // // NOTE: [bassamt] Stubs for TextMode setup funtions. These // are needed so that we can call SlDetectHal during regular boot. // PVOID InfFile = NULL; PVOID WinntSifHandle = NULL; BOOLEAN DisableACPI = FALSE; VOID SlNoMemError( IN ULONG Line, IN PCHAR File ) /*++ Routine Description: This routine does nothing. Arguments: Line - Line number of the error. File - Name of the file with the error. Return Value: None. --*/ { UNREFERENCED_PARAMETER( Line ); UNREFERENCED_PARAMETER( File ); return; } VOID SlBadInfLineError( IN ULONG Line, IN PCHAR INFFile ) /*++ Routine Description: This routine does nothing. Arguments: Line - Line number of the error. INFFile - Supplies a pointer to the INF filename. Return Value: None. --*/ { UNREFERENCED_PARAMETER( Line ); UNREFERENCED_PARAMETER( INFFile ); return; } VOID SlErrorBox( IN ULONG MessageId, IN ULONG Line, IN PCHAR File ) /*++ Routine Description: This routine does nothing. Arguments: MessageId - Id of the text to display. Line - Line number of the of the warning. File - Name of the file where warning is coming from. Return Value: None. --*/ { UNREFERENCED_PARAMETER( MessageId ); UNREFERENCED_PARAMETER( Line ); UNREFERENCED_PARAMETER( File ); return; } VOID SlFriendlyError( IN ULONG uStatus, IN PCHAR pchBadFile, IN ULONG uLine, IN PCHAR pchCodeFile ) /*++ Routine Description: This routine does nothing. Arguments: uStatus - ARC error code pchBadFile - Name of file causing error (Must be given for handled ARC codes. Optional for unhandled codes.) uLine - Line # in source code file where error occurred (only used for unhandled codes.) pchCodeFile - Name of souce code file where error occurred (only used for unhandled codes.) Return Value: None. --*/ { UNREFERENCED_PARAMETER( uStatus ); UNREFERENCED_PARAMETER( pchBadFile ); UNREFERENCED_PARAMETER( uLine ); UNREFERENCED_PARAMETER( pchCodeFile ); return; } VOID SlFatalError( IN ULONG MessageId, ... ) /*++ Routine Description: This routine does nothing. In the context of dynamic HAL detection, we just ignore the error and hope everything is ok. Arguments: MessageId - Supplies ID of message box to be presented. any sprintf-compatible arguments to be inserted in the message box. Return Value: None. --*/ { UNREFERENCED_PARAMETER( MessageId ); return; } ULONG SlGetChar( VOID ) { return 0; } VOID SlPrint( IN PTCHAR FormatString, ... ) { UNREFERENCED_PARAMETER( FormatString ); return; }