/*++ Copyright (c) 1999-2001 Microsoft Corporation Module Name: efifmt.cxx Abstract: This is the main program for the efi version of format. --*/ #pragma warning(disable: 4091) #include "ulib.hxx" #include "wstring.hxx" #include "efickmsg.hxx" #include "error.hxx" #include "ifssys.hxx" #include "rtmsg.h" #include "ifsentry.hxx" #include "fatvol.hxx" #include "layout.hxx" #include "efiwintypes.hxx" extern "C" BOOLEAN InitializeUfat( PVOID DllHandle, ULONG Reason, PCONTEXT Context ); extern "C" BOOLEAN InitializeIfsUtil( PVOID DllHandle, ULONG Reason, PCONTEXT Context ); int __cdecl main( int argc, WCHAR** argv, WCHAR** envp ); int argc; WCHAR ** argv; #if defined(EFI_DEBUG) VOID PrintLoadedImageInfo ( IN EFI_LOADED_IMAGE *LoadedImage ); #endif VOID InvokeAutoFmtMain ( IN EFI_HANDLE ImageHandle, IN EFI_LOADED_IMAGE *LoadedImage ); extern "C" { EFI_STATUS __declspec(dllexport) InitializeEfiFmtApplication( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_LOADED_IMAGE *LoadedImage; /* * Initialize the Library. Set BS, RT, &ST globals * BS = Boot Services RT = RunTime Services * ST = System Table */ InitializeLib (ImageHandle, SystemTable); InitializeShellApplication( ImageHandle, SystemTable ); DEBUG((D_INFO,(CHAR8*)"EFIFMT application started\n")); Print(TEXT("EFI Disk Format Version 0.2\n")); Print(TEXT("Based on EFI Core ")); Print(TEXT("Version %d.%d.%d.%d\n"), EFI_SPECIFICATION_MAJOR_REVISION, EFI_SPECIFICATION_MINOR_REVISION, EFI_FIRMWARE_MAJOR_REVISION, EFI_FIRMWARE_MINOR_REVISION ); BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID**)&LoadedImage); #if 0 PrintLoadedImageInfo (LoadedImage); #endif // call into autofmt. InvokeAutoFmtMain (ImageHandle, LoadedImage); #if 0 EfiWaitForKey(); ST->ConOut->OutputString (ST->ConOut, TEXT("\n\n")); #endif return EFI_SUCCESS; } } // extern "C" UINT16 *MemoryType[] = { TEXT("reserved "), TEXT("LoaderCode"), TEXT("LoaderData"), TEXT("BS_code "), TEXT("BS_data "), TEXT("RT_code "), TEXT("RT_data "), TEXT("available "), TEXT("Unusable "), TEXT("ACPI_recl "), TEXT("ACPI_NVS "), TEXT("MemMapIO "), TEXT("MemPortIO "), TEXT("PAL_code "), TEXT("BUG:BUG: MaxMemoryType") }; VOID InvokeAutoFmtMain ( IN EFI_HANDLE ImageHandle, IN EFI_LOADED_IMAGE *LoadedImage ) { EFI_LOADED_IMAGE *ParentImage; if (!LoadedImage->ParentHandle) { /* * If you are loaded from the EFI boot manager the ParentHandle * is Null. Thus a pure EFI application will not have a parrent. */ DEBUG((D_INFO,(CHAR8*)"\n%HImage was loaded from EFI Boot Manager%N\n")); return; } BS->HandleProtocol (LoadedImage->ParentHandle, &LoadedImageProtocol, (VOID**)&ParentImage); #if 0 Print(TEXT("\n%HImage Parent was %N%s %Hand it passed the following arguments:%N \n %s\n\n"), DevicePathToStr (ParentImage->FilePath),LoadedImage->LoadOptions); #endif { argc = SI->Argc; argv = SI->Argv; DEBUG((D_INFO,(CHAR8*)"Launching main...\n")); // call main. main(argc,argv,NULL); DEBUG((D_INFO,(CHAR8*)"Returned from main...\n")); } } #if defined(EFI_DEBUG) VOID PrintLoadedImageInfo ( IN EFI_LOADED_IMAGE *LoadedImage ) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath; Print(TEXT("\n%HImage was loaded from file %N%s\n"), DevicePathToStr (LoadedImage->FilePath)); BS->HandleProtocol (LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID**)&DevicePath); if (DevicePath) { Print(TEXT("%HImage was loaded from this device %N%s\n"), DevicePathToStr (DevicePath)); } Print(TEXT("\n Image Base is %X"), LoadedImage->ImageBase); Print(TEXT("\n Image Size is %X"), LoadedImage->ImageSize); Print(TEXT("\n Image Code Type %s"), MemoryType[LoadedImage->ImageCodeType]); Print(TEXT("\n Image Data Type %s"), MemoryType[LoadedImage->ImageDataType]); Print(TEXT("\n %d Bytes of Options passed to this Image\n"), LoadedImage->LoadOptionsSize); if (LoadedImage->ParentHandle) { Status = BS->HandleProtocol (LoadedImage->ParentHandle, &DevicePathProtocol, (VOID**)&DevicePath); if (Status == EFI_SUCCESS && DevicePath) { Print(TEXT("Images parent is %s\n\n"), DevicePathToStr (DevicePath)); } } } #endif int __cdecl main( int argc, WCHAR** argv, WCHAR** envp ) /*++ Routine Description: This routine is the main program for AutoFmt Arguments: argc, argv - Supplies the fully qualified NT path name of the the drive to check. The syntax of the autofmt command line is: AUTOFMT drive-name /FS:target-file-system [/V:label] [/Q] [/A:size] [/C] [/S] Return Value: 0 - Success. 1 - Failure. --*/ { if (!InitializeUlib( NULL, ! DLL_PROCESS_DETACH, NULL ) || !InitializeIfsUtil(NULL, ! DLL_PROCESS_DETACH, NULL) || !InitializeUfat(NULL, ! DLL_PROCESS_DETACH, NULL) ) { return 1; } PFAT_VOL fat_volume; PDP_DRIVE dp_drive; EFICHECK_MESSAGE *message = NULL; DSTRING drive_name; DSTRING file_system_name; DSTRING label; DSTRING* plabel; DSTRING fat_name; DSTRING fat32_name; DSTRING raw_name; BOOLEAN quick = FALSE; BOOLEAN compress = FALSE; FORMAT_ERROR_CODE success; BOOLEAN setup_output = FALSE; BOOLEAN textmode_output = FALSE; BOOLEAN drive_already_specified = FALSE; BOOLEAN force_filesystem = FALSE; BOOLEAN showhelp = FALSE; BOOLEAN labelled = FALSE; BIG_INT bigint; ULONG cluster_size = 0; int i; NTSTATUS result; if (!(perrstk = NEW ERRSTACK)) { return 1; } if (!file_system_name.Initialize()) { return 1; } if (!label.Initialize() || NULL == (dp_drive = NEW DP_DRIVE)) { return 1; } // // Parse the arguments. // // if ( argc < 2 ) { // return 1; // } message = NEW EFICHECK_MESSAGE; if (NULL == message || !message->Initialize()) { return 1; } // // The rest of the arguments are flags. // for (i = 1; i < argc; i++) { if (((argv[i][0] == '/' || argv[i][0] == '=') && (argv[i][1] == '?' )) || showhelp ) { showhelp = TRUE; } else if ((argv[i][0] == '/' || argv[i][0] == '-') && (argv[i][1] == 'f' || argv[i][1] == 'F') && (argv[i][2] == 's' || argv[i][2] == 'S') && (argv[i][3] == ':')) { if (!file_system_name.Initialize(&argv[i][4])) { return 1; } force_filesystem = TRUE; DEBUG((D_INFO,(CHAR8*)"fsname: %ws\n", file_system_name.GetWSTR())); } else if ((argv[i][0] == '/' || argv[i][0] == '-') && (argv[i][1] == 'v' || argv[i][1] == 'V') && (argv[i][2] == ':')) { if (!label.Initialize(&argv[i][3])) { return 1; } labelled = TRUE; } else if ((argv[i][0] == '/' || argv[i][0] == '-') && (argv[i][1] == 'a' || argv[i][1] == 'A') && (argv[i][2] == ':')) { // Check to see if the size is specified in Kb if ((argv[i][StrLen(argv[i])-1] == 'k') || (argv[i][StrLen(argv[i])-1] == 'K')) { argv[i][StrLen(argv[i])-1] = '\0'; // remove the K and null terminate the string cluster_size = (ULONG)Atoi(&argv[i][3]) * 1024; } else { cluster_size = (ULONG)Atoi(&argv[i][3]); } } else if (0 == StriCmp(argv[i], TEXT("/Q")) || 0 == StriCmp(argv[i], TEXT("-Q"))) { quick = TRUE; } else if (argv[i][0] != '/' && argv[i][0] != '-') { // it's not a switch, assume it is the drive // we don't allow two drive at the same time if( drive_already_specified ) { message->Set(MSG_FMT_INVALID_DRIVE_SPEC); message->Display(); return 1; } drive_already_specified = TRUE; if ( !drive_name.Initialize( argv[i] ) ) { return 1; } DEBUG((D_INFO,(CHAR8*)"drive name: %ws\n", drive_name.GetWSTR())); } else { // its not any vaild option we know of message->Set(MSG_INVALID_PARAMETER); message->Display("%ws",argv[i]); message->Set(MSG_BLANK_LINE); message->Display(); showhelp = TRUE; } } DEBUG((D_INFO,(CHAR8*)"Parsed Args.\n")); if(showhelp || !drive_already_specified) { message->Set(MSG_FORMAT_INFO); message->Display(); message->Set(MSG_FORMAT_COMMAND_LINE_1); message->Display(); message->Set(MSG_FORMAT_COMMAND_LINE_2); message->Display(); message->Set(MSG_FORMAT_COMMAND_LINE_4); message->Display(); message->Set(MSG_FORMAT_SLASH_V); message->Display(); message->Set(MSG_FORMAT_SLASH_Q); message->Display(); message->Set(MSG_FORMAT_SLASH_F); message->Display(); message->Set(MSG_FORMAT_SUPPORTED_SIZES); message->Display(); return 1; } textmode_output = TRUE; #if 0 // Shouldn't limit the cluster size as long as it is reasonable. if (cluster_size != 0 && cluster_size != 512 && cluster_size != 1024 && cluster_size != 2048 && cluster_size != 4096) { message->Set(MSG_UNSUPPORTED_PARAMETER); message->Display(); DeRegister( argc, argv ); return 1; } #endif DEBUG((D_INFO,(CHAR8*)"Determining file system type.\n")); if (0 == file_system_name.QueryChCount()) { // attempt to get the current filesystem type from disk if (!IFS_SYSTEM::QueryFileSystemName(&drive_name, &file_system_name, &result, NULL)) { message->Set( MSG_FS_NOT_DETERMINED ); message->Display( "%W", &drive_name ); DEBUG((D_ERROR,(CHAR8*)"Unable to determine file system type.\n")); if(result != 0) { message->Set(MSG_CANT_DASD); message->Display(); } return 1; } file_system_name.Strupr(); } if (!fat_name.Initialize("FAT") || !fat32_name.Initialize("FAT32") || !raw_name.Initialize("RAW") ) { return 1; } file_system_name.Strupr(); // // If compression is requested, make sure it's available. // #if 0 if (compress) { message->Set(MSG_COMPRESSION_NOT_AVAILABLE); message->Display("%W", &file_system_name); return 1; } #endif DEBUG((D_INFO,(CHAR8*)"Init DP_DRIVE.\n")); if (!dp_drive->Initialize(&drive_name, message)) { DEBUG((D_ERROR,(CHAR8*)"Failed Init DP_DRIVE.\n")); return 1; } DEBUG((D_INFO,(CHAR8*)"Init DP_DRIVE success.\n")); message->Set(MSG_WARNING_FORMAT); message->Display("%W", &drive_name); if (!message->IsYesResponse(FALSE)) { return 5; } if (dp_drive->IsFloppy()) { DEBUG((D_INFO,(CHAR8*)"**** Is a floppy.\n")); // return 1; BUGBUG should i fail this? } // // Print the "formatting " message. // if (quick) { message->Set(MSG_QUICKFORMATTING_MB); } else { message->Set(MSG_FORMATTING_MB); } if( labelled == FALSE ) { plabel = NULL; } else { plabel = &label; } DEBUG((D_INFO,(CHAR8*)"QuerySector count.\n")); bigint = dp_drive->QuerySectors() * dp_drive->QuerySectorSize() / 1048576; DEBUG((D_INFO,(CHAR8*)"Sector count is %ld.\n",dp_drive->QuerySectors())); DEBUG((D_INFO,(CHAR8*)"Sector size is %d.\n",dp_drive->QuerySectorSize())); DebugAssert(bigint.GetHighPart() == 0); message->Display("%d", bigint.GetLowPart()); #if 0 PART_DESCRIPTOR partdes; UINT32 fatsize; // if the user hasn't forced a filesystem if( force_filesystem == FALSE ) { // if the disk is big enough to put at least FAT16 on it if (dp_drive->QuerySectors() >= (ULONG)MinSectorsFat16(dp_drive->QuerySectorSize())) { DEBUG((D_INFO,(CHAR8*)"Drive is big enough for FAT16 >= %d.\n",MinSectorsFat16(dp_drive->QuerySectorSize()))); partdes.SectorCount = (dp_drive->QuerySectors()).GetQuadPart(); partdes.SectorSize = dp_drive->QuerySectorSize(); partdes.HeaderCount = HEADER_F16; partdes.FatEntrySize = 2; partdes.MinClusterCount = MIN_CLUSTER_F16; partdes.MaxClusterCount = MAX_CLUSTER_F16; partdes.FatType = FAT_TYPE_F16; file_system_name.Initialize(fat_name.QueryWSTR()); // if this disk is big enough for FAT32 if (dp_drive->QuerySectors() >= (ULONG)MinSectorsFat32(dp_drive->QuerySectorSize())) { DEBUG((D_INFO,(CHAR8*)"Drive is big enough for FAT32 >= %d\n",MinSectorsFat32(dp_drive->QuerySectorSize()))); partdes.SectorCount = (dp_drive->QuerySectors()).GetQuadPart(); partdes.SectorSize = dp_drive->QuerySectorSize(); partdes.HeaderCount = HEADER_F32; partdes.FatEntrySize = 4; partdes.MinClusterCount = MIN_CLUSTER_F32; partdes.MaxClusterCount = MAX_CLUSTER_F32; partdes.FatType = FAT_TYPE_F32; file_system_name.Initialize(fat32_name.QueryWSTR()); } // if the user hasn't forced a cluster size, select an appropriate one for him if( cluster_size==0 ) { PickClusterSize(&partdes,(UINT32*)&cluster_size,&fatsize); // note this routine doesn't work for FAT12 cluster_size = cluster_size * dp_drive->QuerySectorSize(); // PickClusterSize return cluster size in sectors DEBUG((D_INFO,(CHAR8*)"User hasn't forced a cluster size, picking %d\n",cluster_size)); } } else { // do the default, which is going to be FAT12 and whatever regular format picks. file_system_name.Initialize(fat_name.QueryWSTR()); } } else { // if the drive is big enough for FAT16 if (dp_drive->QuerySectors() >= (ULONG)MinSectorsFat16(dp_drive->QuerySectorSize())) { // the user forced a file system, did he force a cluster size? if( cluster_size==0 ) { // nope, setup and pick a good size partdes.SectorCount = (dp_drive->QuerySectors()).GetQuadPart(); partdes.SectorSize = dp_drive->QuerySectorSize(); if(file_system_name == fat_name) { partdes.HeaderCount = HEADER_F16; partdes.FatEntrySize = 2; partdes.MinClusterCount = MIN_CLUSTER_F16; partdes.MaxClusterCount = MAX_CLUSTER_F16; partdes.FatType = FAT_TYPE_F16; } else if(file_system_name == fat32_name){ partdes.HeaderCount = HEADER_F32; partdes.FatEntrySize = 4; partdes.MinClusterCount = MIN_CLUSTER_F32; partdes.MaxClusterCount = MAX_CLUSTER_F32; partdes.FatType = FAT_TYPE_F32; } PickClusterSize(&partdes,(UINT32*)&cluster_size,&fatsize); // note this routine doesn't work for FAT12 cluster_size = cluster_size * dp_drive->QuerySectorSize(); // PickClusterSize return cluster size in sectors DEBUG((D_INFO,(CHAR8*)"FS type forced, user hasn't forced a cluster size, picking %d\n",cluster_size)); } } } #endif if (file_system_name == fat_name || file_system_name == fat32_name) { BOOLEAN old_fat_vol = TRUE; DEBUG((D_INFO,(CHAR8*)"This is an old FAT volume.\n")); if( file_system_name == fat32_name ) { old_fat_vol = FALSE; } if( !(fat_volume = NEW FAT_VOL) || NoError != fat_volume->Initialize( &drive_name, message, FALSE, !quick, Unknown )) { DEBUG((D_ERROR,(CHAR8*)"fat_volume init failed.\n")); //return 1; } DEBUG((D_INFO,(CHAR8*)"fat_volume init succeeded.\n")); success = fat_volume->Format(plabel, message, old_fat_vol ? FORMAT_BACKWARD_COMPATIBLE : 0, cluster_size); DEBUG((D_INFO,(CHAR8*)"Format return code: %d\n", success)); DELETE( fat_volume ); } else { DEBUG((D_ERROR,(CHAR8*)"fs not supported.\n")); message->Set( MSG_FS_NOT_SUPPORTED ); message->Display( "%s%W", "EFIFMT", &file_system_name); return 1; } return (success != NoError); }