// AiR-BOOT (c) Copyright 1998-2009 M. Kiewitz // // This file is part of AiR-BOOT // // AiR-BOOT is free software: you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // AiR-BOOT is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY: without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. // // You should have received a copy of the GNU General Public License along with // AiR-BOOT. If not, see . // #include "install.h" // ============================================================================ // Variables // ============================================================================ //CHAR Track0[SECTOR_COUNT * BYTES_PER_SECTOR]; // current track 0 from harddrive //CHAR Bootcode[SECTOR_COUNT * BYTES_PER_SECTOR]; // bootcode image from airboot.bin /* // With the addition of the C DOS-version, a static buffer for both // Track0 and Bootcode would overflow the DGROUP segment. (>64kB) // Placing the buffers in another segment does not work with Open Watcom v1.9. // While the buffers are BSS and should be in segments like FAR_BSS, // Open Watcom places the buffers in FAR_DATA and produces a bloated DOS // executable. Using the same source and then building an OS/2 v1.x // executable does not produce a bloated .EXE, eventhough the segments are // called FAR_DATA and in the middle of the image. // Microsoft C v6.0 displays the same behavior; DOS bloated, OS/2 v1.x ok. // An interesting feat is that when building an OS/2 v1.x executable and then // binding that to produce a FAPI executable does not produce a bloated .EXE // // Also, when experimenting with segments and #pragma data_seg(), some // strange behavior was observed. // WCC: // Explicitly naming a segment and class for the static buffers caused // wcc to keep generating it's default SS: based addressing, eventhough // the segments are not part of DGROUP. // Only the -zu flag corrects this. (DS!=SS) // WPP: // C++ wpp used correct addressing but the segment class in the #pragma // was not honored and the segment name got mangled. // // In both cases the volatile (transient) data would occupy space in the // disk-image. // The only way seems to be putting the buffers in a separate segment using // pragma's, using wcc with the -zu flag and use the wlink ORDER directive // to place the FAR BSS data above the stack acompanied by a NOEMIT modifier. // For this all the class names of the previous segments must be included // in the wlink ORDER directive which would make the link phase dependend // on segment names. This solution does not work for wpp because it mangles // the segment name and overrides the custom class name to FAR_DATA. // // So, these buffers are now dynamically allocated. */ PCHAR Track0 = NULL; // Buffer for Track0 from harddisk. PCHAR Bootcode = NULL; // Buffer for AIRBOOT.BIN image. UCHAR Bootcode_LanguageID = ' '; USHORT Bootcode_Version = 0; USHORT Bootcode_ConfigVersion = 0; UCHAR Status_Code = STATUS_NOTINSTALLED; UCHAR Status_Config = STATUS_NOTINSTALLED; USHORT Installed_CodeVersion = 0; USHORT Installed_ConfigVersion = 0; UCHAR Installed_LanguageID = ' '; BOOL Option_ForceCode = FALSE; BOOL Option_ForceConfig = FALSE; BOOL Option_Silent = FALSE; BOOL Option_CID = FALSE; BOOL Install_Code = FALSE; BOOL Install_Config = FALSE; BOOL Install_IsCorrupt = FALSE; //USHORT StatusCode = 0; PSZ ImpossibleCause = NULL; CHAR TempHidPartTable[45 * 34]; // ============================================================================ // Kidnapped bitfield functions needed to access the packed hideparttable // ============================================================================ /* // Pragma's could be used to interface with the bitfield functions, but I was // not in the mood to examine how they behave when conditions like calling // convention, memory model, optimization, etc. are changed. Especially // optimization generates very different code depending on the -o flags so // it felt a bit 'fragile' to me to use them without further analysis. // So I opted for the 'easy way' of some small prolog code to pass the // parameters to the correct registers required by the core bitfield functions. */ //~ #ifdef __386__ //~ #pragma aux __airboot "*___" parm caller [EBX] [EDX] [ECX] [EAX ESI EDI] value [AL]; //~ #else //~ #pragma aux __airboot "*___" parm caller [DI BX] [DX] [CX] [AX SI] value [AL]; //~ #endif //~ #pragma aux (__airboot) get_bitfield; //~ #pragma aux (__airboot) set_bitfield; /* Prototypes */ void bf_test(); char get_bitfield(char* buffer, char index, char fieldwidth); char set_bitfield(char* buffer, char index, char fieldwidth, char value); //~ #ifdef __386__ //~ #pragma aux get_bitfield parm [EBX] [ECX] [EDX] value [AL]; //~ #pragma aux set_bitfield parm [EBX] [ECX] [EDX] [EAX]; //~ #else //~ #pragma aux get_bitfield value [DL]; //~ #pragma aux set_bitfield parm [BX] [CX] [DX] [AX]; //~ #endif void DumpTrack0(); // In 32-bit mode EBX is used and in 16-bit mode BX, so we abstract it's name. // The rest of the bitfield code uses 16-bit registers because I kidnapped // it from AiR-BOOT. #define dataptr16 "BX" #define dataptr32 "EBX" #ifdef __386__ #define dataptr dataptr32 #else #define dataptr dataptr16 #endif /* // ---------------------------------------------------------------------------- // bf_test -- Test function to analyse code generation // ---------------------------------------------------------------------------- */ void bf_test() { char* b1 = Track0; char* b2 = Bootcode; char i1 = 0x11; char i2 = 0x12; char v1 = 0x83; char v2 = 0x84; char rv1 = 0xf8; char rv2 = 0xf9; rv1 = get_bitfield(b1, i1, 6); rv2 = set_bitfield(b2, i2, 6, v1+v2); } /* // ---------------------------------------------------------------------------- // do_bf_test -- Simple function to test the bitfield functions // ---------------------------------------------------------------------------- */ void do_bf_test() { char buf[512]; int i; for (i=0; i<100; i++) { set_bitfield(buf, i, 6, i); } set_bitfield(buf, 18, 6, 255); set_bitfield(buf, 21, 6, 255); set_bitfield(buf, 33, 6, 255); set_bitfield(buf, 37, 6, 255); for (i=0; i<100; i++) { printf("index: %02d, value: %02d\n", i, get_bitfield(buf, i, 6)); } return; } /* // ---------------------------------------------------------------------------- // get_bitfield -- Get a n-bit wide bitfield at index i from a buffer in memory // ---------------------------------------------------------------------------- // This is code kidnapped from AiR-BOOT and used here to handle the packed // hideparttable. A 'record' in the hideparttable is 34 bytes long and it // can store 45 partition numbers using 6-bits per partition number. // Bitfield widths from 1 to 8 are supported and the maximum buffersize is // 256 bytes. */ char get_bitfield(char* buffer, char index, char fieldwidth) { char rv = 0; // These are used to break-up the far pointer in large-data model 16-bit // code so the buffer can be addressed correctly. // In 32-bit flat mode they will have no effect and in 32-bit large-data // mode (imaginary) they can handle the buffer being in a seperate segment. unsigned dseg = _FP_SEG(buffer); unsigned dptr = _FP_OFF(buffer); // Prolog code. // Handle data-segment and parameters. _asm { push ds ; Save DS from caller. push dseg ; Setup DS to pop ds ; address our segment. (When 16-bit large data-model) mov dl, index ; Index to bitfield in DL. mov dh, fieldwidth ; Width of bitfield in DH. mov dataptr, dptr ; Pointer in [E]BX. } // This is practically a verbatim copy of the core routine from CONV.ASM. // Only a slight modification with regard to [E]BX addressing is made // so it can also function in 32-bit mode. _asm { ; IN: DL = Index to store bitfield ; DH = Bitfield width (1-8) ; [E]BX = Pointer to bitfield array ; OUT: AL = Value of requested bitfield ; AH = Mask value ; Normalize bit-width in DH. dec dh ; Decrement bitfield width to mask invalid values. and dh,07h ; Only 3 bits are significant to determine width. mov cl,dh ; Save for later use to calculate mask. inc dh ; Put back to normalized value. ; Calculate corresponding AND-mask in CH. mov ch,2 ; Were going to shift 2... shl ch,cl ; to obtain the mask corresponding... dec ch ; to the bitfield width. ; Calculate byte-index. mov al,dl ; Index in AL. inc al ; Increment for calculations. mul dh ; Multiply by bitfield width to get bits. mov cl,8 ; Nr. of bits in a byte. div cl ; Divide to get byte index. ; Advance pointer to byte-index. add bl,al ; Advance pointer... adc bh,0 ; to byte index. ; We have to 'carry on' to the high word of EBX if in 32-bit mode. #ifdef __386__ pushf ; Save the possible carry from the last addition. ror ebx,16 ; Get high word of EBX in BX. popf ; Restore possible carry. adc bx,0 ; Add it and... rol ebx,16 ; move back to have a valid 32-bit pointer again. #endif ; Determine if we need 1 or 2 byte access to extract the bitfield. mov cl,ah ; Get remainder in CL. sub cl,dh ; Substract bitfield width to get shift-count. mov ah,0 ; Prepare upper=0 when field spans no byte bound. ; Don't change to xor ah,ah or any CY will be lost. ; Jump if the bitfield does not span byte boundaries. ; (Remainder - bitfield width >= 0) jae CONV_GetBitfieldValue_nospan ; Bit-field spans byte boundaries, so adjust shift-count ; and use AH to get first part of bitfield. add cl,8 ; Adjust shift-count. mov ah,[dataptr] ; Get byte into AH instead. dec dataptr ; Adjust pointer to load rest of bitfield. CONV_GetBitfieldValue_nospan: mov al,[dataptr] ; Load (rest of) bitfield into AL. shr ax,cl ; Shift bitfield to the right. mov ah,ch ; Get mask in AH. and al,ah ; Mask value. } // Epilog code. // Restore caller's DS. // Store return value. _asm { pop ds mov [rv],al } return rv; } /* // ---------------------------------------------------------------------------- // set_bitfield -- Set a n-bit wide bitfield at index i in a buffer in memory // ---------------------------------------------------------------------------- // This is code kidnapped from AiR-BOOT and used here to handle the packed // hideparttable. A 'record' in the hideparttable is 34 bytes long and it // can store 45 partition numbers using 6-bits per partition number. // Bitfield widths from 1 to 8 are supported and the maximum buffersize is // 256 bytes. */ char set_bitfield(char* buffer, char index, char fieldwidth, char value) { // These are used to break-up the far pointer in large-data model 16-bit // code so the buffer can be addressed correctly. // In 32-bit flat mode they will have no effect and in 32-bit large-data // mode (imaginary) they can handle the buffer being in a seperate segment. unsigned dseg = _FP_SEG(buffer); unsigned dptr = _FP_OFF(buffer); // Prolog code. // Handle data-segment and parameters. _asm { push ds ; Save DS from caller. push dseg ; Setup DS to pop ds ; address our segment. (When 16-bit large data-model) mov dl, index ; Index to bitfield in DL. mov dh, fieldwidth ; Width of bitfield in DH. mov dataptr, dptr ; Pointer in [E]BX. mov al, value ; Value we want to poke in AL. } // This is practically a verbatim copy of the core routine from CONV.ASM. // Only a slight modification with regard to [E]BX addressing is made // so it can also function in 32-bit mode. _asm { ; IN: AL = Value to store ; DL = Index to store bitfield ; DH = Bitfield width (1-8) ; [E]BX = Pointer to bitfield array ; OUT: AL = Value of stored bitfield ; AH = Mask value ; Push value for later use. push ax ; Normalize bit-width in DH. dec dh ; Decrement bitfield width to mask invalid values. and dh,07h ; Only 3 bits are significant to determine width. mov cl,dh ; Save for later use to calculate mask. inc dh ; Put back to normalized value. ; Calculate corresponding AND-mask in CH. mov ch,2 ; Were going to shift 2... shl ch,cl ; to obtain the mask corresponding... dec ch ; to the bitfield width. ; Calculate byte-index. mov al,dl ; Index in AL. inc al ; Increment for calculations. mul dh ; Multiply by bitfield width to get bits. mov cl,8 ; Nr. of bits in a byte. div cl ; Divide to get byte index. ; Advance pointer to byte-index. add bl,al ; Advance pointer... adc bh,0 ; to byte index. ; We have to 'carry on' to the high word of EBX if in 32-bit mode. #ifdef __386__ pushf ; Save the possible carry from the last addition. ror ebx,16 ; Get high word of EBX in BX. popf ; Restore possible carry. adc bx,0 ; Add it and... rol ebx,16 ; move back to have a valid 32-bit pointer again. #endif ; Determine if we need 1 or 2 byte access to extract the bitfield. mov cl,ah ; Get remainder in CL. sub cl,dh ; Substract bitfield width to get shift-count. ; Restore value to poke. pop ax ; Jump if the bitfield does not span byte boundaries. ; (Remainder - bitfield width >= 0) jae CONV_SetBitfieldValue_nospan ; Bit-field spans byte boundaries, so adjust shift-count ; and use 16-bit access. add cl,8 ; Adjust shift-count. ; Merge the bitfield to the array. push cx ; Save mask (CH) and shift-count (CL). push ax ; Save value to store. xor ah,ah ; Clear upper byte so we can shift in it. and al,ch ; Mask value. shl ax,cl ; Move the bitfield to the proper location. mov dh,[dataptr] ; Get 1st part of bitfield from array. dec dataptr ; Adjust pointer. mov dl,[dataptr] ; Get 2nd part of bitfield from array. push bx ; We need BX so save it. xor bh,bh ; Clear upper byte so we can shift in it. mov bl,ch ; Put mask in BL. shl bx,cl ; Shift mask to proper location. not bx ; Complement it to mask-out the required bitfield. and dx,bx ; Mask-out the required bitfield. pop bx ; Restore pointer. or ax,dx ; Merge the bitfields. mov [dataptr],al ; Store lower byte. inc dataptr ; Adjust pointer. mov [dataptr],ah ; Store upper byte. pop ax ; Restore value. pop cx ; Restore mask and shift-count. ; Done. jmp CONV_SetBitfieldValue_end CONV_SetBitfieldValue_nospan: ; Merge the bitfield to the array. push cx ; Save mask (CH) and shift-count (CL). push ax ; Save value to store. and al,ch ; Mask value. shl al,cl ; Move the bitfield to the proper location. mov dl,[dataptr] ; Get byte containing bitfield. shl ch,cl ; Shift mask to proper location. not ch ; Complement it to mask-out the required bitfield. and dl,ch ; Mask-out the required bitfield. or al,dl ; Merge the bitfields. mov [dataptr],al ; Store byte containing bitfield. pop ax ; Restore value. pop cx ; Restore mask and shift-count. CONV_SetBitfieldValue_end: mov ah,ch ; Get mask in AH. and al,ah ; Mask value. } // Epilog code. // Restore caller's DS. _asm { pop ds } return value; } // ============================================================================ // Platform-specific helper functions // ============================================================================ /* // Helper functions -- DOS implementation. */ #ifdef PLATFORM_DOS USHORT CountHarddrives (void) { USHORT NumDrives = 0; /* Return the byte at 0040:0075 that contains the nr. of harddisks */ _asm { push es ; We use ES to address the 40h segment. mov ax,40h ; Segment address of DOS BIOS DATA. mov es,ax ; Make ES address it. xor ax,ax ; Clear AX to receive return value. mov al,es:[0075h] ; Nr. of harddisks in AL. pop es ; Restore ES. mov [NumDrives],ax ; Return this value. } return NumDrives; } /* // On DOS this geometry check uses the INT13X value for sectors per track. // On OS/2 the DosDevIOCtl call uses a SPT value from the formatted disk, // irrespective of the physical geometry. */ BOOL HarddriveCheckGeometry (void) { BOOL rv = FALSE; _asm { ; According to Ralf Brown ES:DI=0000:0000 to avoid BIOS quirks. push es push di xor di,di mov es,di ; Get the disk parameters using normal (non-I13X) access. mov ah,08h ; Get Disk Parameters. mov dl,80h ; Boot Disk. int 13h ; Transfer to BIOS. ; Check for errors mov dx,0 ; Assume error. jc end ; CY if error. test ah,ah ; Double check for return-status. jnz end ; AH non-zero if error. ; Check sectors per track to be above 62 and cl,00111111b ; Mask sectors. cmp cl,SECTOR_COUNT ; Compare with max. AiR-BOOT sectors. jbe end ; SECTOR_COUNT or less is not enough. inc dx ; Set to no error. end: mov ax,dx ; Status to AX. ; Store in return value. mov word ptr [rv],ax ; Restore ES:DI pop di pop es } return rv; } BOOL Track0Load (void) { BOOL Success = FALSE; _asm { push es ; ES is used to point to loadbuffer. ; Load the complete AiR-BOOT image from Track0. mov ah,02h ; Read sectors from disk. mov al,SECTOR_COUNT ; Number of sectors to read. mov cx,1 ; Cyl 0, Sector 1. mov dh,0 ; Head 0. mov dl,80h ; Boot Disk. les bx,[Track0] ; Buffer in ES:BX. int 13h ; Transfer to BIOS. ; Check for errors mov dx,0 ; Assume error. jc end ; CY if error. test ah,ah ; Double check status in AH. jnz end ; AH non-zero if error. inc dx ; Set to no error. end: mov ax,dx ; Status to AX. ; Store in return value. mov word ptr [Success],ax ; Restore ES. pop es } return Success; } BOOL Track0Write (void) { BOOL Success = FALSE; _asm { push es ; ES is used to point to savebuffer. ; Save the complete AiR-BOOT image to Track0. mov ah,03h ; Write sectors to disk. mov al,SECTOR_COUNT ; Number of sectors to write. mov cx,1 ; Cyl 0, Sector 1. mov dh,0 ; Head 0. mov dl,80h ; Boot Disk. les bx,[Track0] ; Buffer in ES:BX. int 13h ; Transfer to BIOS. ; Check for errors mov dx,0 ; Assume error. jc end ; CY if error. test ah,ah ; Double check status in AH. jnz end ; AH non-zero if error. inc dx ; Set to no error. end: mov ax,dx ; Status to AX. ; Store in return value. mov word ptr [Success],ax ; Restore ES. pop es } return Success; } void RebootSystem (void) { _asm { ; 65 * 65536 = 4259840 us = 4.2 sec. mov ax,8600h ; BIOS Wait. xor dx,dx ; Micro seconds Low. mov cx,65 ; Micro seconds High. int 15h ; Transfer to BIOS. //~ ; Try reboot via keyboard. //~ mov al,0feh //~ out 64h,al ; Otherwise jump to F000:FFF0. db 0EAh dw 0FFF0h dw 0F000h } return; } #endif /* // Helper functions -- OS/2 implementation. */ #ifdef PLATFORM_OS2 USHORT CountHarddrives (void) { USHORT NumDrives = 0; if (DosPhysicalDisk(INFO_COUNT_PARTITIONABLE_DISKS, &NumDrives, sizeof(NumDrives),NULL, 0) != 0) return 0; return NumDrives; } USHORT OS2_GetIOCTLHandle () { USHORT IOCTLHandle = 0; if (DosPhysicalDisk(INFO_GETIOCTLHANDLE, &IOCTLHandle, sizeof(IOCTLHandle),"1:" , 3) != 0) return 0; return IOCTLHandle; } void OS2_FreeIOCTLHandle (USHORT IOCTLHandle) { DosPhysicalDisk(INFO_FREEIOCTLHANDLE, NULL, 0, &IOCTLHandle, sizeof(IOCTLHandle)); return; } // Special feature for OS/2, finds out boot drive letter and sends this // information to AiR-BOOT, so that it's able to set that information // during boot phase. Otherwise the user would have to set this. UCHAR AutoDriveLetter = ' '; ULONG AutoDriveLetterSerial = 0; void OS2_GetBootAutoDriveLetter (void) { ULONG BootDrive; struct { ULONG ulVSN; VOLUMELABEL vol; } InfoLevel2; DosQuerySysInfo (QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &BootDrive, sizeof(BootDrive)); // BootDrive - 1-A:, 2-B:, 3-C: if ((BootDrive>2) & (!DosQueryFSInfo(BootDrive, FSIL_VOLSER, (PVOID)(&InfoLevel2), sizeof(InfoLevel2)))) { AutoDriveLetter = (UCHAR) BootDrive+0x7D; AutoDriveLetterSerial = InfoLevel2.ulVSN; if (!Option_CID) { printf("%X\n", InfoLevel2.ulVSN); } } } /* // On DOS this geometry check uses the INT13X value for sectors per track. // On OS/2 the DosDevIOCtl call uses a SPT value from the formatted disk, // irrespective of the physical geometry. */ BOOL HarddriveCheckGeometry (void) { USHORT IOCTLHandle; USHORT SectorsPerTrack = 0; DEVICEPARAMETERBLOCK DeviceParmBlock; ULONG ulDataLength; IOCTLHandle = OS2_GetIOCTLHandle(); if (!DosDevIOCtl(IOCTLHandle, IOCTL_PHYSICALDISK, PDSK_GETPHYSDEVICEPARAMS, NULL, 0, NULL, &DeviceParmBlock, sizeof(DeviceParmBlock), &ulDataLength)) SectorsPerTrack = DeviceParmBlock.cSectorsPerTrack; OS2_FreeIOCTLHandle (IOCTLHandle); //if (SectorsPerTrack > 61) return TRUE; if (SectorsPerTrack > SECTOR_COUNT) return TRUE; // OS/2 is only able to support 512-byte/sector media, so we dont need to check this return FALSE; } BOOL Track0Load (void) { USHORT IOCTLHandle; ULONG TrackLayoutLen = sizeof(TRACKLAYOUT)+sizeof(ULONG)*(SECTOR_COUNT-1); TRACKLAYOUT *TrackLayoutPtr = (TRACKLAYOUT*) malloc(TrackLayoutLen); ULONG cbParms = sizeof(TrackLayoutPtr); ULONG cbData = BYTES_PER_SECTOR; int i; BOOL Success = FALSE; IOCTLHandle = OS2_GetIOCTLHandle(); TrackLayoutPtr->bCommand = 0x01; TrackLayoutPtr->usHead = 0; TrackLayoutPtr->usCylinder = 0; TrackLayoutPtr->usFirstSector = 0; TrackLayoutPtr->cSectors = SECTOR_COUNT; for (i=0; iTrackTable[i].usSectorNumber = i+1; TrackLayoutPtr->TrackTable[i].usSectorSize = BYTES_PER_SECTOR; } if (!DosDevIOCtl(IOCTLHandle, IOCTL_PHYSICALDISK, PDSK_READPHYSTRACK, TrackLayoutPtr, cbParms, &cbParms, Track0, cbData, &cbData)) Success = TRUE; OS2_FreeIOCTLHandle (IOCTLHandle); free (TrackLayoutPtr); return Success; } BOOL Track0Write (void) { USHORT IOCTLHandle; ULONG TrackLayoutLen = sizeof(TRACKLAYOUT)+sizeof(ULONG)*(SECTOR_COUNT-1); TRACKLAYOUT *TrackLayoutPtr = (TRACKLAYOUT*) malloc(TrackLayoutLen); ULONG cbParms = sizeof(TrackLayoutPtr); ULONG cbData = BYTES_PER_SECTOR; INT i; BOOL Success = FALSE; IOCTLHandle = OS2_GetIOCTLHandle(); TrackLayoutPtr->bCommand = 0x01; TrackLayoutPtr->usHead = 0; TrackLayoutPtr->usCylinder = 0; TrackLayoutPtr->usFirstSector = 0; TrackLayoutPtr->cSectors = SECTOR_COUNT; for (i=0; iTrackTable[i].usSectorNumber = i+1; TrackLayoutPtr->TrackTable[i].usSectorSize = BYTES_PER_SECTOR; } if (!DosDevIOCtl(IOCTLHandle, IOCTL_PHYSICALDISK, PDSK_WRITEPHYSTRACK, TrackLayoutPtr, cbParms, &cbParms, Track0, cbData, &cbData)) Success = TRUE; OS2_FreeIOCTLHandle (IOCTLHandle); free (TrackLayoutPtr); return Success; } #define CATEGORY_DOSSYS 0xD5 #define FUNCTION_REBOOT 0xAB void RebootSystem (void) { HFILE DosHandle; ULONG DosOpenAction; DosSleep (2000); if (!DosOpen("DOS$", &DosHandle, &DosOpenAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE|OPEN_SHARE_DENYNONE, NULL)) { DosDevIOCtl(DosHandle, CATEGORY_DOSSYS, FUNCTION_REBOOT, NULL, 0, NULL, NULL, 0, NULL); DosSleep (60000); } DosClose(DosHandle); } #endif /* // Helper functions -- Win32 implementation. */ #ifdef PLATFORM_WINNT // Checks, if we are under NT BOOL CheckWindowsVersion (void) { OSVERSIONINFO Version; Version.dwOSVersionInfoSize = sizeof(Version); GetVersionEx(&Version); if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT) return TRUE; if (!Option_CID) { printf(" - This installer is for WindowsNT family only.\n"); printf(" Please use DOS installer for Windows9x.\n"); } return FALSE; } HANDLE WINNT_GetIOCTLHandle (void) { return CreateFile("\\\\.\\physicaldrive0", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); } void WINNT_FreeIOCTLHandle (HANDLE IOCTLHandle) { CloseHandle(IOCTLHandle); } USHORT CountHarddrives (void) { return 1; } BOOL HarddriveCheckGeometry (void) { HANDLE IOCTLHandle; DISK_GEOMETRY Geometry; USHORT SectorsPerTrack = 0; DWORD Dummy; IOCTLHandle = WINNT_GetIOCTLHandle(); if (DeviceIoControl(IOCTLHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &Geometry, sizeof(Geometry), &Dummy, NULL)) SectorsPerTrack = (USHORT) Geometry.SectorsPerTrack; WINNT_FreeIOCTLHandle(IOCTLHandle); //if (SectorsPerTrack > 61) return TRUE; // >60 should also be ok for normal image (60 for image 1 for lvm) if (SectorsPerTrack > SECTOR_COUNT) return TRUE; // Note: This is 1 sector smaller than above !! return FALSE; } BOOL Track0Load (void) { HANDLE IOCTLHandle; DWORD BytesRead = 0; BOOL Success = FALSE; IOCTLHandle = WINNT_GetIOCTLHandle(); SetFilePointer(IOCTLHandle, 0, 0, FILE_BEGIN); if (ReadFile(IOCTLHandle, Track0, SECTOR_COUNT * BYTES_PER_SECTOR, &BytesRead, NULL)) Success = TRUE; WINNT_FreeIOCTLHandle(IOCTLHandle); return Success; } BOOL Track0Write (void) { HANDLE IOCTLHandle; DWORD BytesWritten = 0; BOOL Success = FALSE; IOCTLHandle = WINNT_GetIOCTLHandle(); SetFilePointer(IOCTLHandle, 0, 0, FILE_BEGIN); if (WriteFile(IOCTLHandle, Track0, SECTOR_COUNT * BYTES_PER_SECTOR, &BytesWritten, NULL)) Success = TRUE; WINNT_FreeIOCTLHandle(IOCTLHandle); return Success; } void RebootSystem (void) { HANDLE token; TOKEN_PRIVILEGES tokenpriv; OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token); LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tokenpriv.Privileges[0].Luid); tokenpriv.PrivilegeCount = 1; tokenpriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(token, FALSE, &tokenpriv, 0, NULL, 0); ExitWindowsEx(EWX_REBOOT, 0); } #endif /* // Helper functions -- Linux implementation. */ #ifdef PLATFORM_LINUX USHORT CountHarddrives (void) { USHORT NumDrives = 0; // Implement ! return NumDrives; } BOOL HarddriveCheckGeometry (void) { // Implement ! return FALSE; } BOOL Track0Load (void) { BOOL Success = FALSE; // Implement ! return Success; } BOOL Track0Write (void) { BOOL Success = FALSE; // Implement ! return Success; } void RebootSystem (void) { // Implement ! } #endif // ============================================================================ // Common Code // ============================================================================ USHORT GetChecksumOfSector (USHORT Checksum, PCHAR SectorPtr) { PUSHORT TempPtr = (PUSHORT)SectorPtr; USHORT i; for (i=0; i<256; i++) { Checksum = *TempPtr ^ 0xBABE ^ Checksum; TempPtr++; } if (Checksum==0) Checksum = 1; return Checksum; } // Loads airboot.bin into memory (if possible) and sets some variables // also makes sure that airboot.bin has correct length BOOL LoadBootcodeFromFile (void) { FILE *FileHandle = NULL; ULONG BootcodeSize = 0; // Try to open file... FileHandle = fopen(IMAGE_NAME, "rb"); if (!FileHandle) { if (!Option_CID) { printf("%s not found\n", IMAGE_NAME); } return FALSE; } // Seek to end of file to determine image size... fseek (FileHandle, 0, SEEK_END); BootcodeSize = ftell(FileHandle); if (BootcodeSize!=IMAGE_SIZE && BootcodeSize!=IMAGE_SIZE_60SECS) { fclose (FileHandle); if (!Option_CID) { printf("Invalid %sn\n", IMAGE_NAME); } return FALSE; } // Read whole file into memory... fseek (FileHandle, 0, SEEK_SET); fread (Bootcode, 1, IMAGE_SIZE, FileHandle); fclose (FileHandle); // Extract language and version info... Bootcode_Version = (Bootcode[13] << 8) | Bootcode[14]; Bootcode_LanguageID = Bootcode[15]; Bootcode_ConfigVersion = (Bootcode[0x6C0D] << 8) | Bootcode[0x6C0E]; return TRUE; } /** * Check MBR and AB signatures. * Also check code sectors if AB is installed. * Set global status accordingly. */ void Status_CheckCode (void) { USHORT TotalCodeSectorsUsed = 0; USHORT Checksum = 0; PCHAR SectorPtr = NULL; if (Status_Code==STATUS_IMPOSSIBLE) return; // EZ-Setup check! Status_Code = STATUS_NOTINSTALLED; if ((Track0[0x1FE]!=0x55) || (Track0[0x1FF]!=0xAA)) return; // No MBR signature found, so not installed if (strncmp(&Track0[2], "AiRBOOT", 7)!=0) return; // No AiR-BOOT signature found, so not installed // MBR and AiR-BOOT signature found... TotalCodeSectorsUsed = Track0[0x10]; // 34h/52 in v1.06 SectorPtr = &Track0[1 * BYTES_PER_SECTOR]; // Start at sector 2 // Calculate checksum of code-sectors while (TotalCodeSectorsUsed>0) { Checksum = GetChecksumOfSector(Checksum, SectorPtr); SectorPtr += BYTES_PER_SECTOR; TotalCodeSectorsUsed--; } if (Checksum!=*(PUSHORT) &Track0[0x11]) { Status_Code = STATUS_CORRUPT; return; // Bad checksum for code } // Checksum fine... Installed_LanguageID = Track0[0x0F]; Installed_CodeVersion = (Track0[0x0D] << 8) | Track0[0x0E]; if (Installed_CodeVersion < Bootcode_Version) Status_Code = STATUS_INSTALLEDMGU; // Do upgrade else Status_Code = STATUS_INSTALLED; // Same version installed return; } void Status_CheckConfig (void) { PCHAR ConfigSectorPtr = &Track0[CONFIG_OFFSET]; // Config sector offset hard-coded ! PCHAR SectorPtr = NULL; USHORT Checksum = 0; USHORT ConfigChecksum = 0; USHORT SectorCount = 0; /* // Note that the 'AiRCFG-TABLE' string includes the invisible 0xAD char. */ if (strncmp(ConfigSectorPtr, "AiRCFG-TABLE\xad", 13)==0) { // AiR-BOOT signature found... SectorPtr = &Track0[54 * BYTES_PER_SECTOR]; // Start at sector 55 ConfigChecksum = *(PUSHORT)&Track0[54 * BYTES_PER_SECTOR + 20]; // Remove checksum *(PUSHORT)&Track0[54 * BYTES_PER_SECTOR + 20] = 0; // Config sector secnum hard-coded ! /* // Rousseau: # Keep compatible with v1.07 CRC # // AB v1.07 had bugs in writing the wrong number of AB config sectors. // This is fixed in v1.0.8 but the CRC has to be calculated the "v1.07 way" // otherwise v1.07 SET(A)BOOT and INSTALL2.EXE will think the AB config // is corrupted. // So the CRC is calculated over 5 sectors instead of 7. */ SectorCount = 5; while (SectorCount>0) { Checksum = GetChecksumOfSector(Checksum, SectorPtr); SectorPtr += BYTES_PER_SECTOR; SectorCount--; } // Restore checksum *(PUSHORT) &Track0[54 * BYTES_PER_SECTOR + 20] = ConfigChecksum; // Config sector secnum hard-coded ! if (Checksum != ConfigChecksum) { Status_Config = STATUS_CORRUPT; return; } // Checksum fine Installed_ConfigVersion = (Track0[54 * BYTES_PER_SECTOR + 0x0D] << 8) | Track0[54 * BYTES_PER_SECTOR + 0x0E]; if (Installed_ConfigVersion >= Bootcode_ConfigVersion) { Status_Config = STATUS_INSTALLED; return; } Status_Config = STATUS_INSTALLEDMGU; // Abort if unknown installed config version. if ((Installed_ConfigVersion > 0x110)) { if (!Option_CID) { printf("\n"); printf("Configuration version of installed AiR-BOOT not supported by this installer !\n"); printf("\n"); } exit(1); } // Abort if unknown to-install config version. if ((Bootcode_ConfigVersion > 0x110)) { if (!Option_CID) { printf("\n"); printf("Configuration version of new AiR-BOOT.BIN not supported by this installer !\n"); printf("\n"); } exit(1); } // Those upgrades will copy useful configuration data to the image config // If new configuration data was added, those spaces are not overwritten // Sector 60 (MBR-BackUp) *MUST BE* copied, otherwise it would be lost. // Rousseau: Upgrade from v0.27 if (Installed_ConfigVersion <= 0x27) { // UPGRADE v0.27 and prior versions // Sector 55 // Changes: Offset 69 length 75 - Linux command line // Offset 144 length 1 - Linux kernel partition // Offset 145 Length 11 - Default kernel name // Offset 156 Length 1 - Kernel name terminator 1 // Offset 157 Length 11 - Last kernel name // Offset 168 Length 1 - Kernel name terminator 2 // Offset 169 Length 1 - Ext. partition M$-hack enable // -> Total-length 101 // Offset 432 Length 34 - New IPT entry (BIOS continued) memcpy(&Bootcode[54 * BYTES_PER_SECTOR + 16], &Track0[54 * BYTES_PER_SECTOR + 16], 69 - 16); // CHECKEN !! memcpy(&Bootcode[54 * BYTES_PER_SECTOR + 466], &Track0[54 * BYTES_PER_SECTOR + 466], 46); // CHECKEN !! // Sector 56-57 no changes memcpy(&Bootcode[55*512], &Track0[55 * BYTES_PER_SECTOR], 1024); // Sector 58-59 // Changes: Offset 900 Length 30 - Logical driveletter table memcpy(&Bootcode[57 * BYTES_PER_SECTOR], &Track0[57 * BYTES_PER_SECTOR], 900); // AANPASSEN 900 !! // Sector 60 copy unmodified memcpy(&Bootcode[59 * BYTES_PER_SECTOR], &Track0[59 * BYTES_PER_SECTOR], BYTES_PER_SECTOR); // CHECKEN !! return; } // Rousseau: Upgrade from v0.91 if (Installed_ConfigVersion <= 0x91) { // UPGRADE v0.91 and prior versions // Sector 55-57 no changes memcpy(&Bootcode[54 * BYTES_PER_SECTOR + 16], &Track0[54 * BYTES_PER_SECTOR + 16], BYTES_PER_SECTOR + 1024 - 16); // CHACKEN !! // Sector 58-59 // Changes: Offset 900 Length 30 - Logical driveletter table memcpy(&Bootcode[57 * BYTES_PER_SECTOR], &Track0[57 * BYTES_PER_SECTOR], 900); // AANPASSEN 900 !! // Sector 60/62 copy unmodified memcpy(&Bootcode[59 * BYTES_PER_SECTOR], &Track0[59 * BYTES_PER_SECTOR], BYTES_PER_SECTOR); return; } // UPGRADE to v1.06 format. // We don't need to "upgrade" the configuration to move to v1.06, we simply copy it over. // From Sector 55, 6 sectors in total but never header/version. // Rousseau: We copy two more sectors (8 in total) in the extended (45 partition) version. switch (IMAGE_SIZE) { case IMAGE_SIZE_60SECS: { memcpy(&Bootcode[54 * BYTES_PER_SECTOR + 16], &Track0[54 * BYTES_PER_SECTOR + 16], BYTES_PER_SECTOR * 6 - 16); break; } case IMAGE_SIZE_62SECS: { memcpy(&Bootcode[54 * BYTES_PER_SECTOR + 16], &Track0[54 * BYTES_PER_SECTOR + 16], BYTES_PER_SECTOR * 8 - 16); break; } } /* // Convert v1.06 hideparttable (30x30) to the v1.07 (30x45) format. // Also copy drive-letters to either v1.07 or v1.0.8+ location. */ if ((Installed_ConfigVersion == 0x102) && (Bootcode_ConfigVersion >= 0x107)) { int i,j; char c; //printf("Converting 1.06 -> 1.07 hidepart"); // Copy old hide-part table to new location. memcpy(&Bootcode[0x7400], &Track0[0x7200], 900); // Setup temporary table. memset(TempHidPartTable, 0xff, 45 * 34); // Copy old hide-part table to temporary table. for (i=0; i<30; i++) { for (j=0; j<30; j++) { c = Bootcode[0x7400+i*30+j]; TempHidPartTable[i*45+j] = c; } } // Copy temporary table to final v1.07 location. memcpy(&Bootcode[0x7400], TempHidPartTable, 30 * 45); // Clear drive-letters if version being installed is v1.07. if (Bootcode_ConfigVersion == 0x107) { memset(&Bootcode[0x7946], 0, 45); } // Copy over drive-letters from v1.06 location to v1.08+ location. if ((Bootcode_ConfigVersion >= 0x108) && (Bootcode_ConfigVersion <= 0x110)) { memset(&Bootcode[0x6cb0], 0, 45); memcpy(&Bootcode[0x6cb0], &Track0[0x7584], 30); } } /* // Convert v1.07 hideparttable (30x45) to a packed v1.0.8+ (45x45) format. */ if ((Installed_ConfigVersion < 0x108) && (Bootcode_ConfigVersion <= 0x110)) { int i,j; char c; //printf("Converting to 1.08 packed hidepart"); // Setup temporary table. memset(TempHidPartTable, 0xff, 45 * 34); // Copy old hide-part table to temporary table. // Unpacked table is 30 rows with 45 columns per row. // Packed table is 45 rows with 45 columns per row packed in 34 bytes. for (i=0; i<30; i++) { for (j=0; j<45; j++) { c = Bootcode[0x7400+i*45+j]; // Get unpacked value c = set_bitfield(&TempHidPartTable[i*34], j, 6, c); // Store 6-bit packed value } } // Copy temporary table to final v1.0.8+ location (packed format) memcpy(&Bootcode[0x7400], TempHidPartTable, 45 * 34); // Show LVM Drive Letters. Bootcode[0x6c17] = 1; } return; } // MKW: // Check for prior v0.26 signature // not supported in C version anymore // Don't have this version here for testing and I can't risk breaking // configuration return; } // Checks partition table for valid data BOOL Virus_CheckThisMBR (PCHAR MBRptr) { // Rousseau: adjusted this function USHORT PartitionNo; ////ULONG CHSStart, CHSEnd; //printf("DEBUG: Virus_CheckThisMBR\n"); if (*(PUSHORT)(MBRptr + BYTES_PER_SECTOR - 2)!=0x0AA55) return FALSE; //printf("DEBUG: Virus_CheckThisMBR - Checking Partitions\n"); MBRptr += 446; for (PartitionNo=0; PartitionNo<4; PartitionNo++) { if (*(MBRptr+4) != 0) { /* // Rousseau 2011-02-04: ## Check for GPT ## */ if (*(MBRptr+4) == GPT) { if (!Option_CID) { printf("ERROR: This drive is partitioned with the modern GPT layout.\n"); printf(" AiR-BOOT is currently unable to handle GPT partitioned drives.\n"); printf(" Installation aborted, no changes made.\n"); } exit(2); } /* // Rousseau: 2011-05-05 // Last minute change to have AB install on a disk // with nopartitions on the it. (check !) // It still checks for GPT but will skip the check below. */ continue; //printf("DEBUG: Virus_CheckThisMBR - Partition: %d\n", PartitionNo); // Partition-type defined, analyse partition data ////CHSStart = (*(MBRptr+3) | ((*(MBRptr+2) >> 6) << 8)) << 16; // Cylinder ////CHSStart |= (*(MBRptr+2) & 0x3F) | ((*(MBRptr+1) << 8)); // Sector / Head //printf("DEBUG: Virus_CheckThisMBR - CHSStart: %d\n", CHSStart); // 3F MASK CHECKEN !! ////CHSEnd = (*(MBRptr+7) | ((*(MBRptr+6) >> 6) << 8)) << 16; // Cylinder ////CHSEnd |= (*(MBRptr+6) & 0x3F) | ((*(MBRptr+5) << 8)); // Sector / Head //printf("DEBUG: Virus_CheckThisMBR - CHSEnd: %d\n", CHSEnd); /* // Rousseau 2011-02-03: ## Changed below from < to <= ## // When a partition is above 1024x255x63 (8GiB) the start and end of the partition // in the MBR is the same (1024/255/63) to indicate extended CHS-values. // This made the installer see this as a non-valid entry. // Fixme: This could use some further optimazation like checking if CHS is really 1024/255/63 // to exclude truly faulty partition-entries. // Also depends on conventions: IBM,MS,Partition Magic,... */ /*if (CHSStart 0? //// return TRUE; ////} } // Go to next partition MBRptr += 16; } // No partitions defined/no valid partitions found // Rousseau: Still return TRUE (OK) //return FALSE; return TRUE; } BOOL Virus_CheckCurrentMBR (void) { return Virus_CheckThisMBR((PCHAR) Track0); } BOOL Virus_CheckForBackUpMBR (void) { BOOL bMbrBackup = FALSE; // All versions above v1.06 have expanded tables so the MBR-backup // is located 2 sectors higher in the track0 image. if (Installed_ConfigVersion <= 0x0106) bMbrBackup = Virus_CheckThisMBR((PCHAR) &Track0[59 * BYTES_PER_SECTOR]); else bMbrBackup = Virus_CheckThisMBR((PCHAR) &Track0[61 * BYTES_PER_SECTOR]); return bMbrBackup; } BOOL Virus_CheckForStealth (void) { PCHAR CurPtr = (PCHAR) Track0; USHORT i; for (i=0; i<511; i++) { if (*(PUSHORT)CurPtr == 0x13CD) return FALSE; CurPtr++; } // No CD13h found? possible stealth return TRUE; } // Copies backup MBR into current MBR on current memory copy of track 0 // Rousseau: Two sectors higher in the extended version. void Virus_CopyBackUpMBR (void) { switch (IMAGE_SIZE) { case IMAGE_SIZE_60SECS: { memcpy(Track0, &Track0[59 * BYTES_PER_SECTOR], BYTES_PER_SECTOR); // sector 60 break; } case IMAGE_SIZE_62SECS: { memcpy(Track0, &Track0[61 * BYTES_PER_SECTOR], BYTES_PER_SECTOR); // sector 62 break; } } } void Status_PrintF (ULONG Status, USHORT Version) { switch (Status) { case STATUS_NOTINSTALLED: { if (!Option_CID) { printf("not installed\n"); } break; } case STATUS_CORRUPT: { if (!Option_CID) { printf("not intact\n"); } break; } case STATUS_INSTALLED: case STATUS_INSTALLEDMGU: if (!Option_CID) { printf("intact (v%x.%1d.%1d)", Version>>8, (Version & 0x0F0)>>4, Version & 0x0F); } if (Status==STATUS_INSTALLEDMGU) if (!Option_CID) { printf(", but may be updated"); } if (!Option_CID) { printf("\n"); } break; case STATUS_IMPOSSIBLE: if (!Option_CID) { printf(ImpossibleCause); } break; } } void Language_PrintF(UCHAR LanguageID) { if (Option_CID) return; switch (LanguageID) { case 'E': printf("english"); break; case 'N': printf("dutch"); break; // Changed from 'D' to 'N' case 'G': printf("german"); break; case 'F': printf("french"); break; case 'I': printf("italian"); break; case 'R': printf("russian"); break; case 'S': printf("swedish"); break; case 0xa5: printf("spanish"); break; default: printf("unknown"); } } // Doesn't actually write code/config, but writes it to track0 memory void Install_WriteCode (void) { USHORT TotalCodeSectorsUsed = 0; USHORT SectorCount = 0; USHORT Checksum = 0; PCHAR SectorPtr = NULL; // Calculate checksum for code... TotalCodeSectorsUsed = Bootcode[0x10]; // SECTORS USED CHECKEN !! (34h / 52d in v1.06) SectorPtr = &Bootcode[1 * BYTES_PER_SECTOR]; // Start at sector 2 SectorCount = TotalCodeSectorsUsed; while (SectorCount>0) { Checksum = GetChecksumOfSector(Checksum, SectorPtr); SectorPtr += BYTES_PER_SECTOR; SectorCount--; } *(PUSHORT)&Bootcode[0x11] = Checksum; // Copy MBR till offset 0x1B8 (Windows NT hdd signature location) memcpy(Track0, Bootcode, 0x1B8); // Copy over code sectors... memcpy(&Track0[BYTES_PER_SECTOR], &Bootcode[BYTES_PER_SECTOR], TotalCodeSectorsUsed * BYTES_PER_SECTOR); } void Install_WriteConfig (void) { USHORT SectorCount = 0; USHORT Checksum = 0; PCHAR SectorPtr = NULL; #ifdef PLATFORM_OS2 if (AutoDriveLetter!=0) { // Add DriveLetter Automatic veriables, if set Bootcode[54 * BYTES_PER_SECTOR + 0x1AB] = AutoDriveLetter; // CHECKEN ! *(PULONG)&Bootcode[54 * BYTES_PER_SECTOR + 0x1AC] = AutoDriveLetterSerial; } #endif // Delete current checksum *(PUSHORT)&Bootcode[54 * BYTES_PER_SECTOR + 20] = 0; SectorPtr = &Bootcode[54 * BYTES_PER_SECTOR]; // Start at sector 55 /* // Rousseau: # Keep compatible with v1.07 CRC # // AB v1.07 had bugs in writing the wrong number of AB config sectors. // This is fixed in v1.0.8+ but the CRC has to be calculated the "v1.07 way" // otherwise v1.07 SET(A)BOOT and AIRBOOT2.EXE will think the AB config // is corrupted. // So the CRC is calculated over 5 sectors instead of 7. */ SectorCount = 5; while (SectorCount>0) { Checksum = GetChecksumOfSector(Checksum, SectorPtr); SectorPtr += BYTES_PER_SECTOR; SectorCount--; } *(PUSHORT)&Bootcode[54 * BYTES_PER_SECTOR + 20] = Checksum; // Copy configuration sectors // Rousseau: Two more sectors for extended version. switch (IMAGE_SIZE) { case IMAGE_SIZE_60SECS: { memcpy(&Track0[54 * BYTES_PER_SECTOR], &Bootcode[54 * BYTES_PER_SECTOR], 6 * BYTES_PER_SECTOR); break; } case IMAGE_SIZE_62SECS: { memcpy(&Track0[54 * BYTES_PER_SECTOR], &Bootcode[54 * BYTES_PER_SECTOR], 8 * BYTES_PER_SECTOR); break; } } return; } void DumpTrack0() { int i,j; for (i=27; i<32; i++) { for (j=0; j<16; j++) { printf("%02X",Track0[i*16+j]); } printf("\n"); } } void DoDebug() { USHORT t0codv = 0; USHORT t0cfgv = 0; USHORT bccodv = 0; USHORT bccfgv = 0; //do_bf_test(); printf("\nHardisks : %d\n", CountHarddrives()); printf("\nGEO : %d\n", HarddriveCheckGeometry()); printf("\nTrack0 : %d\n", Track0Load()); printf("\nBootcode : %d\n", LoadBootcodeFromFile()); // Dump Track0 DumpTrack0(); printf("\n\n"); // Dump Bootcode //~ { //~ int i; //~ for (i=0; i<512; i++) { //~ printf("%02X",Bootcode[i]); //~ } //~ } //~ printf("\n\n"); t0codv = Track0[13] << 8 | Track0[14]; printf("t0codv : %04X\n", t0codv); t0cfgv = Track0[0x6c00+13] << 8 | Track0[0x6c00+14]; printf("t0cfgv : %04X\n", t0cfgv); bccodv = Bootcode[13] << 8 | Bootcode[14]; printf("bccodv : %04X\n", bccodv); bccfgv = Bootcode[0x6c00+13] << 8 | Bootcode[0x6c00+14]; printf("bccfgv : %04X\n", bccfgv); return; } // ============================================================================ // Main Entrypoint // ============================================================================ #define MAXCMDPARMLEN 11 int main (int argc, char **argv) { ULONG CurArgument = 0; size_t ArgumentLen = 0; PCHAR StartPos = 0; UCHAR UserKey = ' '; BOOL ExitOnly = FALSE; CHAR TempSpace[MAXCMDPARMLEN+1]; // Check commandline parameters CurArgument = 1; while (CurArgument1)) { StartPos++; ArgumentLen--; if (ArgumentLen>MAXCMDPARMLEN) ArgumentLen = MAXCMDPARMLEN; strncpy((char *) TempSpace, StartPos, ArgumentLen); TempSpace[ArgumentLen] = 0; StartPos = (PCHAR) TempSpace; while (*StartPos!=0) { *StartPos = tolower(*StartPos); StartPos++; } if (strcmp((char *) TempSpace, "forcecode")==0) Option_ForceCode = TRUE; if (strcmp((char *) TempSpace, "forceconfig")==0) Option_ForceConfig = TRUE; if (strcmp((char *) TempSpace, "silent")==0) Option_Silent = TRUE; if (strcmp((char *) TempSpace, "cid")==0) Option_CID = TRUE; } CurArgument++; } // Only support /cid on OS/2 for the moment. // The DOS code behaves quirky with /cid and Win32 is not tested at all. #ifndef PLATFORM_OS2 Option_CID = FALSE; #endif if (Option_CID) { Option_Silent = TRUE; } // Show header. if (!Option_CID) { printf("AiR-BOOT Installer v%s.%s.%s for %s\n", BLDLVL_MAJOR_VERSION, BLDLVL_MIDDLE_VERSION, BLDLVL_MINOR_VERSION, PLATFORM_NAME); printf(" - (c) Copyright 1998-2012 by Martin Kiewitz.\n"); printf("\n-> ...Please wait... <-\n"); } // Allocate buffers for Track0 and 'airboot.bin'. Track0 = malloc(SECTOR_COUNT * BYTES_PER_SECTOR); Bootcode = malloc(SECTOR_COUNT * BYTES_PER_SECTOR); // Exit of allocation failed. if (!(Track0 && Bootcode)) { if (!Option_CID) { printf("- Unable to allocate enough memory, operation aborted!\n"); } exit(4); } //~ DoDebug(); //~ exit(0); #ifdef PLATFORM_WINNT if (CheckWindowsVersion()==FALSE) return 1; #endif if (CountHarddrives()==0) { if (!Option_CID) { printf(" - No physical drives found on this system. Install impossible.\n"); } return 3; // Rouseau: changed from 1 to 3 } if (!Option_CID) { printf(" - Loading bootcode from file..."); } if (LoadBootcodeFromFile()==FALSE) return 1; if (!Option_CID) { printf("ok\n"); } if (!Option_CID) { printf(" - Loading MBR from harddisc..."); } if (!Track0Load()) { if (!Option_CID) { printf("LOAD ERROR!\n"); } return 1; } else { if (!Option_CID) { printf("ok\n"); } } if (!HarddriveCheckGeometry()) { // No EZ-SETUP check here, because we are under 32-bit OS and this // wouldn't make any sense //printf("\nDEBUG: STATUS_IMPOSSIBLE\n"); Status_Code = STATUS_IMPOSSIBLE; ImpossibleCause = "unable to install\n Your harddisc does not have at least 63 sectors per track."; } if (!Option_CID) { printf("\n-> ...Current Status... <-\n"); } Status_CheckCode(); if (!Option_CID) { printf(" - AiR-BOOT is "); } Status_PrintF(Status_Code, Installed_CodeVersion); if (Status_Code==STATUS_IMPOSSIBLE) return 1; Status_CheckConfig(); if (!Option_CID) { printf(" - Configuration is "); } Status_PrintF(Status_Config, Installed_ConfigVersion); // Display language as well, if code installed if ((Status_Code==STATUS_INSTALLED) || (Status_Code==STATUS_INSTALLEDMGU)) { if (!Option_CID) { printf(" - Language is "); } Language_PrintF(Installed_LanguageID); if (!Option_CID) { printf("\n"); } } // ============================================================= // PRE-CHECKING, WHAT WE ARE SUPPOSED TO DO... // ============================================================= if ((Option_ForceCode) || (Status_Code!=STATUS_INSTALLED) || (Installed_LanguageID!=Bootcode_LanguageID)) Install_Code = TRUE; // If LanguageID different or not installed if ((Option_ForceConfig) || (Status_Config!=STATUS_INSTALLED)) Install_Config = TRUE; // If not installed if ((Status_Code==STATUS_CORRUPT) || (Status_Config==STATUS_CORRUPT)) Install_IsCorrupt = TRUE; // If anything is corrupt // ============================================================= // VIRUS // ============================================================= // If-Table // --------- // Code==not installed, Config=not installed -> Check MBR // Code==installed, config==installed -> Check MBR (-> Virus?) // Code==not installed, config==installed -> (-> Virus?) // Code==installed, config==not installed -> Check MBR (-> Virus?) //printf("DEBUG: Status_Code: %d, Status_Config: %d\n", Status_Code, Status_Config); // Rousseau: DEBUG if ((Status_Code==STATUS_NOTINSTALLED) & (Status_Config==STATUS_NOTINSTALLED)) { // Nothing installed, so check MBR, if squashed... if (!Virus_CheckCurrentMBR()) { if (!Option_CID) { printf("\n\n"); printf("AiR-BOOT detected that the data on your harddisc got damaged.\n"); printf("If you had AiR-BOOT installed before: the corruption killed AiR-BOOT completly!\n"); printf("Installation halted.\n"); } return 255; // Rousseau: changed from 1 to 255 } //printf("DEBUG: Installing...\n"); // Rousseau: DEBUG } else { if ((Status_Code==STATUS_NOTINSTALLED) | (!Virus_CheckCurrentMBR())) { // Code not installed, but Config or MBR squashed... // -> Virus proposed, check for backup (if available) if (!Option_CID) { printf("\n\n"); printf("-> ...!ATTENTION!... <-\n"); } if (Virus_CheckForStealth()) if (!Option_CID) { printf("Your system GOT infected by a stealth-virus (or your MBR got trashed).\n"); } else if (!Option_CID) { printf("Probably your system was infected by a virus.\n"); printf("Repairing AiR-BOOT will normally squash the virus.\n"); printf("But to be sure it's gone, you should check your harddisc using a virus-scanner.\n"); } if (!Virus_CheckCurrentMBR()) { // MBR squashed, so check backup and display message if (!Option_CID) { printf("\n"); printf("AiR-BOOT detected that the virus has broken your partition-table.\n"); } if (Virus_CheckForBackUpMBR()) { if (!Option_CID) { printf("Good news: AiR-BOOT has found a (hopefully) functional backup.\n"); printf("Shall I use this backup, instead of the current active one? (Y/N)\n"); } // User selection, Y/N, if he wants to restore MBR // *NOT* CID (silent) able do { UserKey = getch() | 0x20; } while (!((UserKey=='y') | (UserKey=='n'))); if (UserKey=='y') Virus_CopyBackUpMBR(); } else { if (!Option_CID) { printf("Sadly the virus also broke AiR-BOOT's backup. You will have to help yourself.\n"); } } } } } // ============================================================= // MAIN-MENU // ============================================================= if (!Option_CID) { printf("\n-> ...Please press... <-\n"); } if (!Option_CID) { if (Install_IsCorrupt) printf(" - Repair AiR-BOOT "); else if (Status_Code==STATUS_NOTINSTALLED) printf(" - Add AiR-BOOT "); else printf(" - Update/Change AiR-BOOT to "); printf("'v%x.%1d.%1d/", Bootcode_Version>>8, (Bootcode_Version & 0x0F0)>>4, Bootcode_Version & 0x0F); Language_PrintF(Bootcode_LanguageID); printf("' on current system\n"); printf(" - Delete AiR-BOOT from current system\n"); printf(" - Quit without any change\n"); } if (Option_Silent || Option_CID) { // Silent operation? Always add AiR-BOOT then UserKey = 'a'; } else { do { UserKey = getch() | 0x20; } while (!((UserKey=='a') || (UserKey=='r') || (UserKey=='u') || (UserKey=='d') || (UserKey=='q'))); } if (!Option_CID) { printf("\n\n\n-------------------------------------------------------------------------------\n"); } switch (UserKey) { case 'a': case 'r': case 'u': { if (Install_Code || Install_Config) { if (!Option_CID) { printf("Add/Repair/Update AiR-BOOT in progress...\n"); } #ifdef PLATFORM_OS2 OS2_GetBootAutoDriveLetter(); #endif if (Install_Code) { if (!Option_CID) { printf(" \xfe Writing AiR-BOOT code..."); } //~ DumpTrack0(); Install_WriteCode(); //~ DumpTrack0(); if (!Option_CID) { printf("ok\n"); } } if (Install_Config) { if (!Option_CID) { printf(" \xfe Writing AiR-BOOT configuration..."); } Install_WriteConfig(); if (!Option_CID) { printf("ok\n"); } } if (!Track0Write()) { if (!Option_CID) { printf("SAVE ERROR!\n"); } return 1; } if (!Option_CID) { printf("\n"); printf("Your copy of AiR-BOOT is now fully functional.\n"); if (!Option_Silent) { printf("Please hit ESC to exit AiR-BOOT installer or ENTER to reboot your system...\n"); } } if (Option_Silent || Option_CID) { // Silent operation? Always reboot system (shall we do this really?) // No, otherwise installing from MiniLVM will reboot the system // which is not what the user would expect. //UserKey = 0x0D; UserKey = 0x1B; } else { do { UserKey = getch(); // React on ENTER or ESC } while (!((UserKey==0x0D) || (UserKey==0x1B))); } if (UserKey==0x0D) { // ENTER reboots system... (if not in OS/2 install mode) /* // Rousseau: ## Disable Reboot when installing eComStation ## // In the install-environment, the MEMDRIVE env-var is defined. // So, only reboot if this env-var is not defined. */ if (!getenv("MEMDRIVE")) { if (!Option_CID) { printf("Now rebooting system...\n"); } RebootSystem(); } ExitOnly = TRUE; } } else { if (!Option_CID) { printf(" \xfe All components of AiR-BOOT are intact and up-to-date. Nothing to do.\n"); } ExitOnly = TRUE; } break; } case 'd': { if (!Option_CID) { printf(" \xfe Removing AiR-BOOT automatically is not possible at this time.\n"); } #ifdef PLATFORM_OS2 if (!Option_CID) { printf(" You may remove AiR-BOOT manually by entering \"FDISK /MBR\" or \"LVM /NEWMBR:1\"\n"); printf(" in commandline.\n"); } #endif #ifdef PLATFORM_WINNT if (!Option_CID) { printf(" You may remove AiR-BOOT manually by entering \"FDISK /MBR\" in commandline.\n"); } #endif ExitOnly = TRUE; break; } default: break; } if (ExitOnly) { if (!(Option_CID || Option_Silent)) { printf("\n"); printf("Please hit ENTER to exit AiR-BOOT installer...\n"); while (getch()!=0x0D); } } // Free the buffer memory. if (Track0) free(Track0); if (Bootcode) free(Bootcode); return 0; }