From 5dc512f7c3e8feeb28f3a8eebdc5a9ad7e4dbb31 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Fri, 17 Jan 2003 13:18:15 +0000 Subject: [PATCH] Prepared bootloader installation. svn path=/trunk/; revision=4022 --- reactos/subsys/system/usetup/bootsup.c | 282 +++++++++++++++++ reactos/subsys/system/usetup/bootsup.h | 37 +++ reactos/subsys/system/usetup/filesup.c | 48 ++- reactos/subsys/system/usetup/filesup.h | 6 +- reactos/subsys/system/usetup/inicache.c | 382 ++++++++++++++++++++++-- reactos/subsys/system/usetup/inicache.h | 35 ++- reactos/subsys/system/usetup/makefile | 6 +- reactos/subsys/system/usetup/partlist.c | 72 ++++- reactos/subsys/system/usetup/partlist.h | 11 +- reactos/subsys/system/usetup/usetup.c | 262 ++++++++++++---- 10 files changed, 1049 insertions(+), 92 deletions(-) create mode 100644 reactos/subsys/system/usetup/bootsup.c create mode 100644 reactos/subsys/system/usetup/bootsup.h diff --git a/reactos/subsys/system/usetup/bootsup.c b/reactos/subsys/system/usetup/bootsup.c new file mode 100644 index 00000000000..87fd1c32c9c --- /dev/null +++ b/reactos/subsys/system/usetup/bootsup.c @@ -0,0 +1,282 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS text-mode setup + * FILE: subsys/system/usetup/bootsup.c + * PURPOSE: Bootloader support functions + * PROGRAMMER: Eric Kohl + */ + +#include +#include + +#include "usetup.h" +#include "inicache.h" +#include "bootsup.h" + + +/* FUNCTIONS ****************************************************************/ + + +static VOID +CreateCommonFreeLoaderSections(PINICACHE IniCache) +{ + PINICACHESECTION IniSection; + + /* Create "FREELOADER" section */ + IniSection = IniCacheAppendSection(IniCache, + L"FREELOADER"); + +#if 0 +MessageLine=Welcome to FreeLoader! +MessageLine=Copyright (c) 2002 by Brian Palmer +MessageLine= +MessageBox=Edit your FREELDR.INI file to change your boot settings. +#endif + + /* DefaultOS=ReactOS */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"DefaultOS", + L"ReactOS"); + + /* Timeout=10 */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"TimeOut", + L"10"); + + + /* Create "Display" section */ + IniSection = IniCacheAppendSection(IniCache, + L"Display"); + + /* DisplayMode=NORMAL_VGA */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"DisplayMode", + L"NORMAL_VGA"); + + /* TitleText=Boot Menu */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"TitleText", + L"Boot Menu"); + + /* StatusBarColor=Cyan */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"StatusBarColor", + L"Cyan"); + + /* StatusBarTextColor=Black */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"StatusBarTextColor", + L"Black"); + + /* BackdropTextColor=White */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"BackdropTextColor", + L"White"); + + /* BackdropColor=Blue */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"BackdropColor", + L"Blue"); + + /* BackdropFillStyle=Medium */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"BackdropFillStyle", + L"Medium"); + + /* TitleBoxTextColor=White */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"TitleBoxTextColor", + L"White"); + + /* TitleBoxColor=Red */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"TitleBoxColor", + L"Red"); + + /* MessageBoxTextColor=White */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"MessageBoxTextColor", + L"White"); + + /* MessageBoxColor=Blue */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"MessageBoxColor", + L"Blue"); + + /* MenuTextColor=White */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"MenuTextColor", + L"White"); + + /* MenuColor=Blue */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"MenuColor", + L"Blue"); + + /* TextColor=Yellow */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"TextColor", + L"Yellow"); + + /* SelectedTextColor=Black */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"SelectedTextColor", + L"Black"); + + /* SelectedColor=Gray */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"SelectedColor", + L"Gray"); +} + + +NTSTATUS +CreateFreeLoaderIniForDos(PWCHAR IniPath, + PWCHAR SystemPath) +{ + PINICACHE IniCache; + PINICACHESECTION IniSection; + + IniCache = IniCacheCreate(); + + CreateCommonFreeLoaderSections(IniCache); + + /* Create "OperatingSystems" section */ + IniSection = IniCacheAppendSection(IniCache, + L"OperatingSystems"); + + /* REACTOS=ReactOS */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"REACTOS", + L"ReactOS"); + + /* DOS=Dos/Windows */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"DOS", + L"DOS/Windows"); + + /* Create "REACTOS" section */ + IniSection = IniCacheAppendSection(IniCache, + L"REACTOS"); + + /* BootType=ReactOS */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"BootType", + L"ReactOS"); + + /* SystemPath=multi(0)disk(0)rdisk(0)partition(1)\reactos */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"SystemPath", + SystemPath); + + /* Options=/DEBUGPORT=SCREEN */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"Options", + L"/DEBUGPORT=SCREEN"); + + + /* Kernel=\REACTOS\SYSTEM32\NTOSKRNL.EXE */ +#if 0 + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"Options", + L"/DEBUGPORT=SCREEN"); +#endif + + /* Hal=\REACTOS\SYSTEM32\HAL.DLL */ +#if 0 + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"Hal", + L"/DEBUGPORT=SCREEN"); +#endif + + /* Create "DOS" section */ + IniSection = IniCacheAppendSection(IniCache, + L"DOS"); + + /* BootType=BootSector */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"BootType", + L"BootSector"); + + /* BootSector=BOOTDOS.BIN */ + IniCacheInsertKey(IniSection, + NULL, + INSERT_LAST, + L"BootSector", + L"BOOTDOS.BIN"); + + IniCacheSave(IniCache, IniPath); + IniCacheDestroy(IniCache); +} + +/* EOF */ \ No newline at end of file diff --git a/reactos/subsys/system/usetup/bootsup.h b/reactos/subsys/system/usetup/bootsup.h new file mode 100644 index 00000000000..41c44a357bf --- /dev/null +++ b/reactos/subsys/system/usetup/bootsup.h @@ -0,0 +1,37 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: bootsup.h,v 1.1 2003/01/17 13:18:15 ekohl Exp $ + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS text-mode setup + * FILE: subsys/system/usetup/bootsup.h + * PURPOSE: Bootloader support functions + * PROGRAMMER: Eric Kohl + */ + +#ifndef __BOOTSUP_H__ +#define __BOOTSUP_H__ + +NTSTATUS +CreateFreeLoaderIniForDos(PWCHAR IniPath, + PWCHAR SystemPath); + + +#endif /* __BOOTSUP_H__ */ + +/* EOF */ diff --git a/reactos/subsys/system/usetup/filesup.c b/reactos/subsys/system/usetup/filesup.c index e4ac99038e6..b9dc5650028 100644 --- a/reactos/subsys/system/usetup/filesup.c +++ b/reactos/subsys/system/usetup/filesup.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: filesup.c,v 1.3 2003/01/11 16:03:55 hbirr Exp $ +/* $Id: filesup.c,v 1.4 2003/01/17 13:18:15 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/filesup.c @@ -276,4 +276,50 @@ CHECKPOINT1; return(STATUS_SUCCESS); } + +BOOLEAN +DoesFileExist(PWSTR PathName, + PWSTR FileName) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING Name; + WCHAR FullName[MAX_PATH]; + HANDLE FileHandle; + NTSTATUS Status; + + wcscpy(FullName, PathName); + if (FileName != NULL) + { + if (FileName[0] != L'\\') + wcscat(FullName, L"\\"); + wcscat(FullName, FileName); + } + + RtlInitUnicodeString(&Name, + FullName); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_READ_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_ALERT); + if (!NT_SUCCESS(Status)) + { +CHECKPOINT1; + return(FALSE); + } + + NtClose(FileHandle); + + return(TRUE); +} + /* EOF */ diff --git a/reactos/subsys/system/usetup/filesup.h b/reactos/subsys/system/usetup/filesup.h index 412d8cd1c1c..a428373d67b 100644 --- a/reactos/subsys/system/usetup/filesup.h +++ b/reactos/subsys/system/usetup/filesup.h @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: filesup.h,v 1.2 2002/11/23 01:55:27 ekohl Exp $ +/* $Id: filesup.h,v 1.3 2003/01/17 13:18:15 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/filesup.h @@ -34,6 +34,10 @@ NTSTATUS SetupCopyFile(PWCHAR SourceFileName, PWCHAR DestinationFileName); +BOOLEAN +DoesFileExist(PWSTR PathName, + PWSTR FileName); + #endif /* __FILESUP_H__ */ diff --git a/reactos/subsys/system/usetup/inicache.c b/reactos/subsys/system/usetup/inicache.c index 7bafbbe0b0f..eb182c5f559 100644 --- a/reactos/subsys/system/usetup/inicache.c +++ b/reactos/subsys/system/usetup/inicache.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: inicache.c,v 1.1 2002/11/13 18:25:18 ekohl Exp $ +/* $Id: inicache.c,v 1.2 2003/01/17 13:18:15 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/inicache.c @@ -53,12 +53,12 @@ IniCacheFreeKey(PINICACHEKEY Key) Key->Name = NULL; } - if (Key->Value != NULL) + if (Key->Data != NULL) { RtlFreeHeap(ProcessHeap, 0, - Key->Value); - Key->Value = NULL; + Key->Data); + Key->Data = NULL; } RtlFreeHeap(ProcessHeap, @@ -129,8 +129,8 @@ static PINICACHEKEY IniCacheAddKey(PINICACHESECTION Section, PCHAR Name, ULONG NameLength, - PCHAR Value, - ULONG ValueLength) + PCHAR Data, + ULONG DataLength) { PINICACHEKEY Key; ULONG i; @@ -140,8 +140,8 @@ IniCacheAddKey(PINICACHESECTION Section, if (Section == NULL || Name == NULL || NameLength == 0 || - Value == NULL || - ValueLength == 0) + Data == NULL || + DataLength == 0) { DPRINT("Invalid parameter\n"); return(NULL); @@ -180,10 +180,10 @@ IniCacheAddKey(PINICACHESECTION Section, Key->Name[NameLength] = 0; - Key->Value = RtlAllocateHeap(ProcessHeap, - 0, - (ValueLength + 1) * sizeof(WCHAR)); - if (Key->Value == NULL) + Key->Data = RtlAllocateHeap(ProcessHeap, + 0, + (DataLength + 1) * sizeof(WCHAR)); + if (Key->Data == NULL) { DPRINT("RtlAllocateHeap() failed\n"); RtlFreeHeap(ProcessHeap, @@ -196,11 +196,11 @@ IniCacheAddKey(PINICACHESECTION Section, } /* Copy value data */ - for (i = 0; i < ValueLength; i++) + for (i = 0; i < DataLength; i++) { - Key->Value[i] = (WCHAR)Value[i]; + Key->Data[i] = (WCHAR)Data[i]; } - Key->Value[ValueLength] = 0; + Key->Data[DataLength] = 0; if (Section->FirstKey == NULL) @@ -711,7 +711,7 @@ IniCacheGetSection(PINICACHE Cache, return(NULL); } - /* iterate through list of sections */ + /* Iterate through list of sections */ Section = Cache->FirstSection; while (Section != NULL) { @@ -734,17 +734,17 @@ IniCacheGetSection(PINICACHE Cache, NTSTATUS IniCacheGetKey(PINICACHESECTION Section, PWCHAR KeyName, - PWCHAR *KeyValue) + PWCHAR *KeyData) { PINICACHEKEY Key; - if (Section == NULL || KeyName == NULL || KeyValue == NULL) + if (Section == NULL || KeyName == NULL || KeyData == NULL) { DPRINT("Invalid parameter\n"); return(STATUS_INVALID_PARAMETER); } - *KeyValue = NULL; + *KeyData = NULL; Key = IniCacheFindKey(Section, KeyName, wcslen(KeyName)); if (Key == NULL) @@ -752,7 +752,7 @@ IniCacheGetKey(PINICACHESECTION Section, return(STATUS_INVALID_PARAMETER); } - *KeyValue = Key->Value; + *KeyData = Key->Data; return(STATUS_SUCCESS); } @@ -761,12 +761,12 @@ IniCacheGetKey(PINICACHESECTION Section, PINICACHEITERATOR IniCacheFindFirstValue(PINICACHESECTION Section, PWCHAR *KeyName, - PWCHAR *KeyValue) + PWCHAR *KeyData) { PINICACHEITERATOR Iterator; PINICACHEKEY Key; - if (Section == NULL || KeyName == NULL || KeyValue == NULL) + if (Section == NULL || KeyName == NULL || KeyData == NULL) { DPRINT("Invalid parameter\n"); return(NULL); @@ -780,7 +780,7 @@ IniCacheFindFirstValue(PINICACHESECTION Section, } *KeyName = Key->Name; - *KeyValue = Key->Value; + *KeyData = Key->Data; Iterator = (PINICACHEITERATOR)RtlAllocateHeap(ProcessHeap, 0, @@ -801,11 +801,11 @@ IniCacheFindFirstValue(PINICACHESECTION Section, BOOLEAN IniCacheFindNextValue(PINICACHEITERATOR Iterator, PWCHAR *KeyName, - PWCHAR *KeyValue) + PWCHAR *KeyData) { PINICACHEKEY Key; - if (Iterator == NULL || KeyName == NULL || KeyValue == NULL) + if (Iterator == NULL || KeyName == NULL || KeyData == NULL) { DPRINT("Invalid parameter\n"); return(FALSE); @@ -819,7 +819,7 @@ IniCacheFindNextValue(PINICACHEITERATOR Iterator, } *KeyName = Key->Name; - *KeyValue = Key->Value; + *KeyData = Key->Data; Iterator->Key = Key; @@ -838,4 +838,334 @@ IniCacheFindClose(PINICACHEITERATOR Iterator) Iterator); } + +PINICACHEKEY +IniCacheInsertKey(PINICACHESECTION Section, + PINICACHEKEY AnchorKey, + INSERTATION_TYPE InsertationType, + PWCHAR Name, + PWCHAR Data) +{ + PINICACHEKEY Key; + ULONG i; + + Key = NULL; + + if (Section == NULL || + Name == NULL || + *Name == 0 || + Data == NULL || + *Data == 0) + { + DPRINT("Invalid parameter\n"); + return(NULL); + } + + /* Allocate key buffer */ + Key = (PINICACHEKEY)RtlAllocateHeap(ProcessHeap, + 0, + sizeof(INICACHEKEY)); + if (Key == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return(NULL); + } + RtlZeroMemory(Key, + sizeof(INICACHEKEY)); + + /* Allocate name buffer */ + Key->Name = RtlAllocateHeap(ProcessHeap, + 0, + (wcslen(Name) + 1) * sizeof(WCHAR)); + if (Key->Name == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, + 0, + Key); + return(NULL); + } + + /* Copy value name */ + wcscpy(Key->Name, Name); + + /* Allocate data buffer */ + Key->Data = RtlAllocateHeap(ProcessHeap, + 0, + (wcslen(Data) + 1) * sizeof(WCHAR)); + if (Key->Data == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, + 0, + Key->Name); + RtlFreeHeap(ProcessHeap, + 0, + Key); + return(NULL); + } + + /* Copy value data */ + wcscpy(Key->Data, Data); + + /* Insert key into section */ + if (Section->FirstKey == NULL) + { + Section->FirstKey = Key; + Section->LastKey = Key; + } + else if ((InsertationType == INSERT_FIRST) || + ((InsertationType == INSERT_BEFORE) && ((AnchorKey == NULL) || (AnchorKey == Section->FirstKey)))) + { + /* Insert at the head of the list */ + Section->FirstKey->Prev = Key; + Key->Next = Section->FirstKey; + Section->FirstKey = Key; + } + else if ((InsertationType == INSERT_BEFORE) && (AnchorKey != NULL)) + { + /* Insert before the anchor key */ + Key->Next = AnchorKey; + Key->Prev = AnchorKey->Prev; + AnchorKey->Prev->Next = Key; + AnchorKey->Prev = Key; + } + else if ((InsertationType == INSERT_LAST) || + ((InsertationType == INSERT_AFTER) && ((AnchorKey == NULL) || (AnchorKey == Section->LastKey)))) + { + Section->LastKey->Next = Key; + Key->Prev = Section->LastKey; + Section->LastKey = Key; + } + else if ((InsertationType == INSERT_AFTER) && (AnchorKey != NULL)) + { + /* Insert before the anchor key */ + Key->Next = AnchorKey->Next; + Key->Prev = AnchorKey; + AnchorKey->Next->Prev = Key; + AnchorKey->Next = Key; + } + + return(Key); +} + + +PINICACHE +IniCacheCreate(VOID) +{ + PINICACHE Cache; + + /* Allocate inicache header */ + Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap, + 0, + sizeof(INICACHE)); + if (Cache == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return(NULL); + } + + /* Initialize inicache header */ + RtlZeroMemory(Cache, + sizeof(INICACHE)); + + return(Cache); +} + + +NTSTATUS +IniCacheSave(PINICACHE Cache, + PWCHAR FileName) +{ + UNICODE_STRING Name; + PINICACHESECTION Section; + PINICACHEKEY Key; + ULONG BufferSize; + PCHAR Buffer; + PCHAR Ptr; + ULONG Len; + NTSTATUS Status; + + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER Offset; + HANDLE FileHandle; + + + /* Calculate required buffer size */ + BufferSize = 0; + Section = Cache->FirstSection; + while (Section != NULL) + { + BufferSize += (Section->Name ? wcslen(Section->Name) : 0) + + 4; /* "[]\r\n" */ + + Key = Section->FirstKey; + while (Key != NULL) + { + BufferSize += wcslen(Key->Name) + + (Key->Data ? wcslen(Key->Data) : 0) + + 3; /* "=\r\n" */ + Key = Key->Next; + } + + Section = Section->Next; + if (Section != NULL) + BufferSize += 2; /* extra "\r\n" at end of each section */ + } + BufferSize++; /* Null-terminator */ + + DPRINT1("BufferSize: %lu\n", BufferSize); + + /* Allocate file buffer */ + Buffer = RtlAllocateHeap(ProcessHeap, + 0, + BufferSize); + if (Buffer == NULL) + { + DPRINT1("RtlAllocateHeap() failed\n"); + return(STATUS_INSUFFICIENT_RESOURCES); + } + RtlZeroMemory(Buffer, BufferSize); + + /* Fill file buffer */ + Ptr = Buffer; + Section = Cache->FirstSection; + while (Section != NULL) + { + Len = sprintf(Ptr, "[%S]\r\n", Section->Name); + Ptr += Len; + + Key = Section->FirstKey; + while (Key != NULL) + { + Len = sprintf(Ptr, "%S=%S\r\n", Key->Name, Key->Data); + Ptr += Len; + Key = Key->Next; + } + + Section = Section->Next; + if (Section != NULL) + { + Len = sprintf(Ptr, "\r\n"); + Ptr += Len; + } + } + + /* Create ini file */ + RtlInitUnicodeString(&Name, + FileName); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + 0, + NULL, + NULL); + + Status = NtCreateFile(&FileHandle, + FILE_WRITE_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OVERWRITE_IF, + FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY, + NULL, + 0); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtCreateFile() failed (Status %lx)\n", Status); + RtlFreeHeap(ProcessHeap, + 0, + Buffer); + return(Status); + } + + Offset.QuadPart = 0LL; + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + BufferSize, + &Offset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + NtClose(FileHandle); + RtlFreeHeap(ProcessHeap, + 0, + Buffer); + return(Status); + } + + NtClose(FileHandle); + + RtlFreeHeap(ProcessHeap, + 0, + Buffer); + + return(STATUS_SUCCESS); +} + + +PINICACHESECTION +IniCacheAppendSection(PINICACHE Cache, + PWCHAR Name) +{ + PINICACHESECTION Section = NULL; + ULONG i; + + if (Cache == NULL || Name == NULL || *Name == 0) + { + DPRINT("Invalid parameter\n"); + return(NULL); + } + + Section = (PINICACHESECTION)RtlAllocateHeap(ProcessHeap, + 0, + sizeof(INICACHESECTION)); + if (Section == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + return(NULL); + } + RtlZeroMemory(Section, + sizeof(INICACHESECTION)); + + /* Allocate and initialize section name */ + Section->Name = RtlAllocateHeap(ProcessHeap, + 0, + (wcslen(Name) + 1) * sizeof(WCHAR)); + if (Section->Name == NULL) + { + DPRINT("RtlAllocateHeap() failed\n"); + RtlFreeHeap(ProcessHeap, + 0, + Section); + return(NULL); + } + + /* Copy section name */ + wcscpy(Section->Name, Name); + + /* Append section */ + if (Cache->FirstSection == NULL) + { + Cache->FirstSection = Section; + Cache->LastSection = Section; + } + else + { + Cache->LastSection->Next = Section; + Section->Prev = Cache->LastSection; + Cache->LastSection = Section; + } + + return(Section); +} + /* EOF */ diff --git a/reactos/subsys/system/usetup/inicache.h b/reactos/subsys/system/usetup/inicache.h index 4320b670144..c25c846bd5b 100644 --- a/reactos/subsys/system/usetup/inicache.h +++ b/reactos/subsys/system/usetup/inicache.h @@ -32,7 +32,7 @@ typedef struct _INICACHEKEY { PWCHAR Name; - PWCHAR Value; + PWCHAR Data; struct _INICACHEKEY *Next; struct _INICACHEKEY *Prev; @@ -65,6 +65,14 @@ typedef struct _PINICACHEITERATOR } INICACHEITERATOR, *PINICACHEITERATOR; +typedef enum +{ + INSERT_FIRST, + INSERT_BEFORE, + INSERT_AFTER, + INSERT_LAST +} INSERTATION_TYPE; + /* FUNCTIONS ****************************************************************/ NTSTATUS @@ -81,24 +89,43 @@ IniCacheGetSection(PINICACHE Cache, NTSTATUS IniCacheGetKey(PINICACHESECTION Section, PWCHAR KeyName, - PWCHAR *KeyValue); + PWCHAR *KeyData); PINICACHEITERATOR IniCacheFindFirstValue(PINICACHESECTION Section, PWCHAR *KeyName, - PWCHAR *KeyValue); + PWCHAR *KeyData); BOOLEAN IniCacheFindNextValue(PINICACHEITERATOR Iterator, PWCHAR *KeyName, - PWCHAR *KeyValue); + PWCHAR *KeyData); VOID IniCacheFindClose(PINICACHEITERATOR Iterator); +PINICACHEKEY +IniCacheInsertKey(PINICACHESECTION Section, + PINICACHEKEY AnchorKey, + INSERTATION_TYPE InsertationType, + PWCHAR Name, + PWCHAR Data); + +PINICACHE +IniCacheCreate(VOID); + +NTSTATUS +IniCacheSave(PINICACHE Cache, + PWCHAR FileName); + +PINICACHESECTION +IniCacheAppendSection(PINICACHE Cache, + PWCHAR Name); + + #endif /* __INICACHE_H__ */ /* EOF */ diff --git a/reactos/subsys/system/usetup/makefile b/reactos/subsys/system/usetup/makefile index 669ee3dc016..80fa8a018b7 100644 --- a/reactos/subsys/system/usetup/makefile +++ b/reactos/subsys/system/usetup/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.6 2002/12/06 21:39:03 ekohl Exp $ +# $Id: makefile,v 1.7 2003/01/17 13:18:15 ekohl Exp $ PATH_TO_TOP = ../../.. @@ -12,8 +12,8 @@ TARGET_INSTALLDIR = system32 TARGET_CFLAGS = -D__NTAPP__ -TARGET_OBJECTS = $(TARGET_NAME).o console.o drivesup.o filequeue.o filesup.o \ - inicache.o partlist.o progress.o +TARGET_OBJECTS = $(TARGET_NAME).o bootsup.o console.o drivesup.o filequeue.o \ + filesup.o inicache.o partlist.o progress.o include $(PATH_TO_TOP)/rules.mak diff --git a/reactos/subsys/system/usetup/partlist.c b/reactos/subsys/system/usetup/partlist.c index 04cecdd649d..89185baeb26 100644 --- a/reactos/subsys/system/usetup/partlist.c +++ b/reactos/subsys/system/usetup/partlist.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: partlist.c,v 1.5 2002/11/28 19:20:37 ekohl Exp $ +/* $Id: partlist.c,v 1.6 2003/01/17 13:18:15 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/partlist.c @@ -104,6 +104,7 @@ AddPartitionList(ULONG DiskNumber, PartEntry->PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart; PartEntry->PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber, PartEntry->PartType = LayoutBuffer->PartitionEntry[i].PartitionType; + PartEntry->Active = LayoutBuffer->PartitionEntry[i].BootIndicator; PartEntry->DriveLetter = GetDriveLetter(DiskNumber, LayoutBuffer->PartitionEntry[i].PartitionNumber); @@ -817,8 +818,8 @@ ScrollUpPartitionList(PPARTLIST List) BOOL -GetPartitionData(PPARTLIST List, - PPARTDATA Data) +GetSelectedPartition(PPARTLIST List, + PPARTDATA Data) { PDISKENTRY DiskEntry; PPARTENTRY PartEntry; @@ -873,4 +874,69 @@ GetPartitionData(PPARTLIST List, return(TRUE); } + +BOOL +GetActiveBootPartition(PPARTLIST List, + PPARTDATA Data) +{ + PDISKENTRY DiskEntry; + PPARTENTRY PartEntry; + ULONG i; + + if (List->CurrentDisk >= List->DiskCount) + return(FALSE); + + DiskEntry = &List->DiskArray[0]; + + if (DiskEntry->FixedDisk == FALSE) + return(FALSE); + + for (i = 0; i < DiskEntry->PartCount; i++) + { + if (DiskEntry->PartArray[i].Active) + { + PartEntry = &DiskEntry->PartArray[i]; + + if (PartEntry->Used == FALSE) + return(FALSE); + + /* Copy disk-specific data */ + Data->DiskSize = DiskEntry->DiskSize; + Data->DiskNumber = DiskEntry->DiskNumber; + Data->Port = DiskEntry->Port; + Data->Bus = DiskEntry->Bus; + Data->Id = DiskEntry->Id; + + /* Copy driver name */ + RtlInitUnicodeString(&Data->DriverName, + NULL); + if (DiskEntry->DriverName.Length != 0) + { + Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap, + 0, + DiskEntry->DriverName.MaximumLength); + if (Data->DriverName.Buffer != NULL) + { + Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength; + Data->DriverName.Length = DiskEntry->DriverName.Length; + RtlCopyMemory(Data->DriverName.Buffer, + DiskEntry->DriverName.Buffer, + DiskEntry->DriverName.MaximumLength); + } + } + + /* Copy partition-specific data */ + Data->PartSize = PartEntry->PartSize; + Data->PartNumber = PartEntry->PartNumber; + Data->PartType = PartEntry->PartType; + Data->DriveLetter = PartEntry->DriveLetter; + + return(TRUE); + } + } + + return(FALSE); +} + + /* EOF */ diff --git a/reactos/subsys/system/usetup/partlist.h b/reactos/subsys/system/usetup/partlist.h index 8fe09ad7151..c5436f243c8 100644 --- a/reactos/subsys/system/usetup/partlist.h +++ b/reactos/subsys/system/usetup/partlist.h @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: partlist.h,v 1.5 2002/11/28 19:20:37 ekohl Exp $ +/* $Id: partlist.h,v 1.6 2003/01/17 13:18:15 ekohl Exp $ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: subsys/system/usetup/partlist.h @@ -50,6 +50,7 @@ typedef struct _PARTENTRY ULONGLONG PartSize; ULONG PartNumber; ULONG PartType; + BOOLEAN Active; CHAR DriveLetter; CHAR VolumeLabel[17]; @@ -119,8 +120,12 @@ VOID ScrollUpPartitionList(PPARTLIST List); BOOL -GetPartitionData(PPARTLIST List, - PPARTDATA Data); +GetSelectedPartition(PPARTLIST List, + PPARTDATA Data); + +BOOL +GetActiveBootPartition(PPARTLIST List, + PPARTDATA Data); #endif /* __PARTLIST_H__ */ diff --git a/reactos/subsys/system/usetup/usetup.c b/reactos/subsys/system/usetup/usetup.c index 06a801fff28..91c2297cf14 100644 --- a/reactos/subsys/system/usetup/usetup.c +++ b/reactos/subsys/system/usetup/usetup.c @@ -36,6 +36,7 @@ #include "inicache.h" #include "filequeue.h" #include "progress.h" +#include "bootsup.h" #define START_PAGE 0 @@ -48,7 +49,8 @@ #define PREPARE_COPY_PAGE 7 #define INSTALL_DIRECTORY_PAGE 8 #define FILE_COPY_PAGE 9 -#define INIT_SYSTEM_PAGE 10 +#define REGISTRY_PAGE 10 +#define BOOT_LOADER_PAGE 11 #define REPAIR_INTRO_PAGE 20 @@ -72,11 +74,18 @@ HANDLE ProcessHeap; BOOLEAN PartDataValid; PARTDATA PartData; -WCHAR InstallDir[51]; +BOOLEAN ActivePartitionValid; +PARTDATA ActivePartition; UNICODE_STRING SourcePath; UNICODE_STRING SourceRootPath; +UNICODE_STRING InstallPath; +UNICODE_STRING DestinationPath; +UNICODE_STRING DestinationRootPath; + +UNICODE_STRING SystemRootPath; /* Path to the active partition */ + PINICACHE IniCache; HSPFILEQ SetupFileQueue = NULL; @@ -627,6 +636,7 @@ InstallIntroPage(PINPUT_RECORD Ir) static ULONG SelectPartitionPage(PINPUT_RECORD Ir) { + WCHAR PathBuffer[MAX_PATH]; PPARTLIST PartList; SHORT xScreen; SHORT yScreen; @@ -641,6 +651,9 @@ SelectPartitionPage(PINPUT_RECORD Ir) SetStatusText(" Please wait..."); + RtlFreeUnicodeString(&DestinationPath); + RtlFreeUnicodeString(&DestinationRootPath); + GetScreenSize(&xScreen, &yScreen); PartList = CreatePartitionList(2, 19, xScreen - 3, yScreen - 3); @@ -678,8 +691,28 @@ SelectPartitionPage(PINPUT_RECORD Ir) } else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ { - PartDataValid = GetPartitionData(PartList, &PartData); + PartDataValid = GetSelectedPartition(PartList, + &PartData); + ActivePartitionValid = GetActiveBootPartition(PartList, + &ActivePartition); DestroyPartitionList(PartList); + + RtlFreeUnicodeString(&DestinationRootPath); + swprintf(PathBuffer, + L"\\Device\\Harddisk%lu\\Partition%lu", + PartData.DiskNumber, + PartData.PartNumber); + RtlCreateUnicodeString(&DestinationRootPath, + PathBuffer); + + RtlFreeUnicodeString(&SystemRootPath); + swprintf(PathBuffer, + L"\\Device\\Harddisk%lu\\Partition%lu", + ActivePartition.DiskNumber, + ActivePartition.PartNumber); + RtlCreateUnicodeString(&SystemRootPath, + PathBuffer); + return(SELECT_FILE_SYSTEM_PAGE); } @@ -846,6 +879,8 @@ CheckFileSystemPage(PINPUT_RECORD Ir) static ULONG InstallDirectoryPage(PINPUT_RECORD Ir) { + WCHAR PathBuffer[MAX_PATH]; + WCHAR InstallDir[51]; ULONG Length; SetTextXY(6, 8, "Setup installs ReactOS files onto the selected partition. Choose a"); @@ -876,6 +911,21 @@ InstallDirectoryPage(PINPUT_RECORD Ir) } else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ { + /* Create 'DestinationPath' string */ + RtlFreeUnicodeString(&InstallPath); + RtlCreateUnicodeString(&InstallPath, + InstallDir); + + /* Create 'DestinationPath' string */ + RtlFreeUnicodeString(&DestinationPath); + wcscpy(PathBuffer, + DestinationRootPath.Buffer); + if (InstallDir[0] != L'\\') + wcscat(PathBuffer, + L"\\"); + wcscat(PathBuffer, InstallDir); + RtlCreateUnicodeString(&DestinationPath, + PathBuffer); return(PREPARE_COPY_PAGE); } @@ -1048,14 +1098,8 @@ PrepareCopyPage(PINPUT_RECORD Ir) * Install directories like '\reactos\test' are not handled yet. */ - /* Build full install directory name */ - swprintf(PathBuffer, - L"\\Device\\Harddisk%lu\\Partition%lu", - PartData.DiskNumber, - PartData.PartNumber); - if (InstallDir[0] != L'\\') - wcscat(PathBuffer, L"\\"); - wcscat(PathBuffer, InstallDir); + /* Get destination path */ + wcscpy(PathBuffer, DestinationPath.Buffer); /* Remove trailing backslash */ Length = wcslen(PathBuffer); @@ -1095,10 +1139,7 @@ PrepareCopyPage(PINPUT_RECORD Ir) { DPRINT("Absolute Path: '%S'\n", KeyValue); - swprintf(PathBuffer, - L"\\Device\\Harddisk%lu\\Partition%lu", - PartData.DiskNumber, - PartData.PartNumber); + wcscpy(PathBuffer, DestinationRootPath.Buffer); wcscat(PathBuffer, KeyValue); DPRINT("FullPath: '%S'\n", PathBuffer); @@ -1106,14 +1147,7 @@ PrepareCopyPage(PINPUT_RECORD Ir) else if (KeyValue[0] != L'\\') { DPRINT("RelativePath: '%S'\n", KeyValue); - swprintf(PathBuffer, - L"\\Device\\Harddisk%lu\\Partition%lu", - PartData.DiskNumber, - PartData.PartNumber); - - if (InstallDir[0] != L'\\') - wcscat(PathBuffer, L"\\"); - wcscat(PathBuffer, InstallDir); + wcscpy(PathBuffer, DestinationPath.Buffer); wcscat(PathBuffer, L"\\"); wcscat(PathBuffer, KeyValue); @@ -1214,7 +1248,6 @@ FileCopyCallback(PVOID Context, static ULONG FileCopyPage(PINPUT_RECORD Ir) { - WCHAR TargetRootPath[MAX_PATH]; COPYCONTEXT CopyContext; SHORT xScreen; SHORT yScreen; @@ -1232,14 +1265,9 @@ FileCopyPage(PINPUT_RECORD Ir) xScreen - 7, yScreen - 10); - swprintf(TargetRootPath, - L"\\Device\\Harddisk%lu\\Partition%lu", - PartData.DiskNumber, - PartData.PartNumber); - SetupCommitFileQueue(SetupFileQueue, - TargetRootPath, - InstallDir, + DestinationRootPath.Buffer, + InstallPath.Buffer, (PSP_FILE_CALLBACK)FileCopyCallback, &CopyContext); @@ -1262,7 +1290,7 @@ FileCopyPage(PINPUT_RECORD Ir) } else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ { - return(INIT_SYSTEM_PAGE); + return(REGISTRY_PAGE); } } @@ -1272,17 +1300,14 @@ FileCopyPage(PINPUT_RECORD Ir) static ULONG -InitSystemPage(PINPUT_RECORD Ir) +RegistryPage(PINPUT_RECORD Ir) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; + UNICODE_STRING ValueName; HANDLE KeyHandle; NTSTATUS Status; - WCHAR TargetPath[MAX_PATH]; - UNICODE_STRING ValueName; - - SetTextXY(6, 8, "Initializing system settings"); @@ -1290,7 +1315,6 @@ InitSystemPage(PINPUT_RECORD Ir) SetTextXY(6, 14, "Update registry hives"); - SetTextXY(6, 16, "Install/update boot manager"); SetStatusText(" Please wait..."); @@ -1314,20 +1338,12 @@ InitSystemPage(PINPUT_RECORD Ir) RtlInitUnicodeStringFromLiteral(&ValueName, L"InstallPath"); - swprintf(TargetPath, - L"\\Device\\Harddisk%lu\\Partition%lu", - PartData.DiskNumber, - PartData.PartNumber); - if (InstallDir[0] != L'\\') - wcscat(TargetPath, L"\\"); - wcscat(TargetPath, InstallDir); - Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, - (PVOID)TargetPath, - wcslen(TargetPath) * sizeof(WCHAR)); + (PVOID)DestinationPath.Buffer, + DestinationPath.Length); NtClose(KeyHandle); if (!NT_SUCCESS(Status)) { @@ -1351,6 +1367,136 @@ InitSystemPage(PINPUT_RECORD Ir) + SetStatusText(" ENTER = Continue F3 = Quit"); + + while(TRUE) + { + ConInKey(Ir); + + if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && + (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ + { + if (ConfirmQuit(Ir) == TRUE) + return(QUIT_PAGE); + break; + } + else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return(BOOT_LOADER_PAGE); + } + } + + return(REGISTRY_PAGE); +} + + +static ULONG +BootLoaderPage(PINPUT_RECORD Ir) +{ + WCHAR SrcPath[MAX_PATH]; + WCHAR DstPath[MAX_PATH]; + PINICACHE IniCache; + PINICACHESECTION IniSection; + + SetTextXY(6, 8, "Installing the boot loader"); + + SetStatusText(" Please wait..."); + + if (ActivePartitionValid == FALSE) + { + SetTextXY(6, 10, "Error: no active partition found"); + for(;;); + } + + if (ActivePartition.PartType == PARTITION_ENTRY_UNUSED) + { + SetTextXY(6, 10, "Error: active partition invalid (unused)"); + for(;;); + } + + if (ActivePartition.PartType == 0x0A) + { + /* OS/2 boot manager partition */ + SetTextXY(6, 12, "Found OS/2 boot manager"); + + } + else if (ActivePartition.PartType == 0x83) + { + /* Linux ext2 partition */ + SetTextXY(6, 12, "Found Linux ext2 partition"); + + } + else if (ActivePartition.PartType == PARTITION_IFS) + { + /* NTFS partition */ + SetTextXY(6, 12, "Found NTFS partition"); + + } + else if ((ActivePartition.PartType == PARTITION_FAT_12) || + (ActivePartition.PartType == PARTITION_FAT_16) || + (ActivePartition.PartType == PARTITION_HUGE) || + (ActivePartition.PartType == PARTITION_XINT13) || + (ActivePartition.PartType == PARTITION_FAT32) || + (ActivePartition.PartType == PARTITION_FAT32_XINT13)) + { + /* FAT or FAT 32 partition */ + PrintTextXY(6, 10, "System path: '%wZ'", &SystemRootPath); + + if (DoesFileExist(SystemRootPath.Buffer, L"ntldr") == TRUE || + DoesFileExist(SystemRootPath.Buffer, L"boot.ini") == TRUE) + { + /* Search root directory for 'ntldr' and 'boot.ini'. */ + SetTextXY(6, 12, "Found Microsoft Windows NT/2000/XP boot loader"); + + + } + else if (DoesFileExist(SystemRootPath.Buffer, L"io.sys") == TRUE || + DoesFileExist(SystemRootPath.Buffer, L"msdos.sys") == TRUE) + { + /* Search for root directory for 'io.sys' and 'msdos.sys'. */ + SetTextXY(6, 12, "Found Microsoft DOS or Windows 9x boot loader"); + + /* Copy FreeLoader to the boot partition */ + wcscpy(SrcPath, SourceRootPath.Buffer); + wcscat(SrcPath, L"\\loader\\freeldr.sys"); + wcscpy(DstPath, SystemRootPath.Buffer); + wcscat(DstPath, L"\\freeldr.sys"); + + PrintTextXY(6, 14, "Copy: %S ==> %S", SrcPath, DstPath); + + SetupCopyFile(SrcPath, DstPath); + + /* Create freeldr.ini */ + wcscpy(DstPath, SystemRootPath.Buffer); + wcscat(DstPath, L"\\freeldr.ini"); + + CreateFreeLoaderIniForDos(DstPath, + DestinationPath.Buffer); + + /* Copy current bootsector to 'BOOTSECT.DOS' */ + if ((ActivePartition.PartType == PARTITION_FAT32) || + (ActivePartition.PartType == PARTITION_FAT32_XINT13)) + { + + } + else + { + + } + } + else + { + + SetTextXY(6, 12, "No or unknown boot loader found"); + + } + } + else + { + /* unknown partition */ + SetTextXY(6, 12, "Unknown partition found"); + } + SetStatusText(" ENTER = Continue F3 = Quit"); while(TRUE) @@ -1370,10 +1516,11 @@ InitSystemPage(PINPUT_RECORD Ir) } } - return(INIT_SYSTEM_PAGE); + return(BOOT_LOADER_PAGE); } + static ULONG QuitPage(PINPUT_RECORD Ir) { @@ -1445,6 +1592,15 @@ NtProcessStartup(PPEB Peb) PartDataValid = FALSE; + /* Initialize global unicode strings */ + RtlInitUnicodeString(&SourcePath, NULL); + RtlInitUnicodeString(&SourceRootPath, NULL); + RtlInitUnicodeString(&InstallPath, NULL); + RtlInitUnicodeString(&DestinationPath, NULL); + RtlInitUnicodeString(&DestinationRootPath, NULL); + RtlInitUnicodeString(&SystemRootPath, NULL); + + Page = START_PAGE; while (Page != REBOOT_PAGE) { @@ -1503,8 +1659,12 @@ NtProcessStartup(PPEB Peb) Page = FileCopyPage(&Ir); break; - case INIT_SYSTEM_PAGE: - Page = InitSystemPage(&Ir); + case REGISTRY_PAGE: + Page = RegistryPage(&Ir); + break; + + case BOOT_LOADER_PAGE: + Page = BootLoaderPage(&Ir); break;