1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- bconf.c
- Abstract:
- This module implements the Boot Configuration Library.
- Author:
- Evan Green 20-Feb-2014
- Environment:
- Any
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/lib/bconf.h>
- #include "bconfp.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // Define some macros for memory allocation.
- //
- #define BcAllocate(_Context, _Size) (_Context)->AllocateFunction(_Size)
- #define BcFree(_Context, _Memory) (_Context)->FreeFunction(_Memory)
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the initial string table allocation size.
- //
- #define INITIAL_BOOT_CONFIGURATION_STRING_TABLE_SIZE 1024
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- BcpParseBootEntry (
- PBOOT_CONFIGURATION_CONTEXT Context,
- ULONG EntryIndex,
- PBOOT_ENTRY *Entry
- );
- VOID
- BcpDestroyBootEntries (
- PBOOT_CONFIGURATION_CONTEXT Context
- );
- KSTATUS
- BcpValidateHeader (
- PBOOT_CONFIGURATION_CONTEXT Context
- );
- KSTATUS
- BcpReadString (
- PBOOT_CONFIGURATION_CONTEXT Context,
- ULONG StringOffset,
- PSTR *String
- );
- KSTATUS
- BcpAddToStringTable (
- PBOOT_CONFIGURATION_CONTEXT Context,
- PSTR String,
- PULONG StringIndex,
- PVOID *StringTable,
- PULONG StringTableSize,
- PULONG StringTableCapacity
- );
- PSTR
- BcpCopyString (
- PBOOT_CONFIGURATION_CONTEXT Context,
- PSTR String
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- BcInitializeContext (
- PBOOT_CONFIGURATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine initializes the given boot configuration context.
- Arguments:
- Context - Supplies a pointer to the context to initialize. The caller must
- have filled in the allocate and free functions, optionally filled in
- the file data, and zeroed the rest of the structure.
- Return Value:
- Status code.
- --*/
- {
- if ((Context->AllocateFunction == NULL) ||
- (Context->FreeFunction == NULL)) {
- ASSERT(FALSE);
- return STATUS_INVALID_PARAMETER;
- }
- Context->BootEntries = NULL;
- Context->BootEntryCount = 0;
- return STATUS_SUCCESS;
- }
- VOID
- BcDestroyContext (
- PBOOT_CONFIGURATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine destroys the given boot configuration context. It will free
- all resources contained in the structure, including the file data.
- Arguments:
- Context - Supplies a pointer to the context to destroy.
- Return Value:
- None.
- --*/
- {
- BcpDestroyBootEntries(Context);
- if (Context->FileData != NULL) {
- BcFree(Context, Context->FileData);
- Context->FileData = NULL;
- }
- Context->FileDataSize = 0;
- return;
- }
- VOID
- BcDestroyBootEntry (
- PBOOT_CONFIGURATION_CONTEXT Context,
- PBOOT_ENTRY Entry
- )
- /*++
- Routine Description:
- This routine destroys the given boot entry, freeing all its resources.
- Arguments:
- Context - Supplies a pointer to the context containing the entry.
- Entry - Supplies a pointer to the entry to destroy.
- Return Value:
- None.
- --*/
- {
- if (Entry->Name != NULL) {
- BcFree(Context, Entry->Name);
- }
- if (Entry->LoaderArguments != NULL) {
- BcFree(Context, Entry->LoaderArguments);
- }
- if (Entry->KernelArguments != NULL) {
- BcFree(Context, Entry->KernelArguments);
- }
- if (Entry->LoaderPath != NULL) {
- BcFree(Context, Entry->LoaderPath);
- }
- if (Entry->KernelPath != NULL) {
- BcFree(Context, Entry->KernelPath);
- }
- if (Entry->SystemPath != NULL) {
- BcFree(Context, Entry->SystemPath);
- }
- BcFree(Context, Entry);
- return;
- }
- KSTATUS
- BcReadBootConfigurationFile (
- PBOOT_CONFIGURATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine parses the boot configuration file out into boot entries that
- can be manipulated by consumers of this library.
- Arguments:
- Context - Supplies a pointer to the context. The file data and file data
- size must have been filled in by the caller.
- Return Value:
- Status code.
- --*/
- {
- PBOOT_ENTRY *EntryArray;
- ULONG EntryIndex;
- PBOOT_CONFIGURATION_HEADER Header;
- KSTATUS Status;
- EntryArray = NULL;
- Header = NULL;
- //
- // Destroy any previous boot entries.
- //
- BcpDestroyBootEntries(Context);
- if ((Context->FileData == NULL) || (Context->FileDataSize == 0)) {
- Status = STATUS_NOT_INITIALIZED;
- goto ReadBootConfigurationFileEnd;
- }
- //
- // Validate the header (which checksums the whole file as well).
- //
- Status = BcpValidateHeader(Context);
- if (!KSUCCESS(Status)) {
- goto ReadBootConfigurationFileEnd;
- }
- Header = Context->FileData;
- Context->GlobalConfiguration.Key = Header->Key;
- Context->GlobalConfiguration.DefaultBootEntry = NULL;
- Context->GlobalConfiguration.BootOnce = NULL;
- Context->GlobalConfiguration.Timeout = Header->Timeout;
- EntryArray = BcAllocate(Context, sizeof(PVOID) * Header->EntryCount);
- if (EntryArray == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ReadBootConfigurationFileEnd;
- }
- RtlZeroMemory(EntryArray, sizeof(PVOID) * Header->EntryCount);
- for (EntryIndex = 0; EntryIndex < Header->EntryCount; EntryIndex += 1) {
- Status = BcpParseBootEntry(Context,
- EntryIndex,
- &(EntryArray[EntryIndex]));
- if (!KSUCCESS(Status)) {
- goto ReadBootConfigurationFileEnd;
- }
- }
- //
- // Set the new array of boot entries.
- //
- Context->BootEntries = EntryArray;
- Context->BootEntryCount = Header->EntryCount;
- Status = STATUS_SUCCESS;
- ReadBootConfigurationFileEnd:
- if (!KSUCCESS(Status)) {
- if (EntryArray != NULL) {
- for (EntryIndex = 0;
- EntryIndex < Header->EntryCount;
- EntryIndex += 1) {
- BcDestroyBootEntry(Context, EntryArray[EntryIndex]);
- }
- BcFree(Context, EntryArray);
- EntryArray = NULL;
- }
- }
- return Status;
- }
- KSTATUS
- BcWriteBootConfigurationFile (
- PBOOT_CONFIGURATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine writes the boot entries into the file buffer.
- Arguments:
- Context - Supplies a pointer to the context. If there is existing file
- data it will be freed, and new file data will be allocated.
- Return Value:
- Status code.
- --*/
- {
- UINTN AllocationSize;
- PBOOT_ENTRY Entry;
- ULONG EntryIndex;
- PBOOT_CONFIGURATION_ENTRY FileEntries;
- PBOOT_CONFIGURATION_ENTRY FileEntry;
- PBOOT_CONFIGURATION_HEADER FinalHeader;
- BOOT_CONFIGURATION_HEADER Header;
- PVOID NewFileData;
- KSTATUS Status;
- PVOID StringTable;
- ULONG StringTableCapacity;
- ULONG StringTableSize;
- FileEntries = NULL;
- NewFileData = NULL;
- StringTable = NULL;
- StringTableCapacity = 0;
- StringTableSize = 0;
- //
- // Initialize the header.
- //
- RtlZeroMemory(&Header, sizeof(BOOT_CONFIGURATION_HEADER));
- Header.DefaultEntry = -1;
- Header.BootOnce = -1;
- //
- // Create the boot entries array.
- //
- AllocationSize = Context->BootEntryCount * sizeof(BOOT_CONFIGURATION_ENTRY);
- FileEntries = BcAllocate(Context, AllocationSize);
- if (FileEntries == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto WriteBootConfigurationFileEnd;
- }
- RtlZeroMemory(FileEntries, AllocationSize);
- //
- // Create each of the boot entries, adding strings to the table along the
- // way.
- //
- for (EntryIndex = 0;
- EntryIndex < Context->BootEntryCount;
- EntryIndex += 1) {
- Entry = Context->BootEntries[EntryIndex];
- FileEntry = &(FileEntries[EntryIndex]);
- //
- // Re-number the boot entry ID numbers. Also save this new ID back into
- // the boot entry.
- //
- FileEntry->Id = EntryIndex + 1;
- Entry->Id = FileEntry->Id;
- FileEntry->Flags = Entry->Flags;
- FileEntry->DebugDevice = Entry->DebugDevice;
- RtlCopyMemory(&(FileEntry->DiskId),
- &(Entry->DiskId),
- BOOT_DISK_ID_SIZE);
- RtlCopyMemory(&(FileEntry->PartitionId),
- &(Entry->PartitionId),
- BOOT_PARTITION_ID_SIZE);
- Status = BcpAddToStringTable(Context,
- Entry->Name,
- &(FileEntry->Name),
- &StringTable,
- &StringTableSize,
- &StringTableCapacity);
- if (!KSUCCESS(Status)) {
- goto WriteBootConfigurationFileEnd;
- }
- Status = BcpAddToStringTable(Context,
- Entry->LoaderArguments,
- &(FileEntry->LoaderArguments),
- &StringTable,
- &StringTableSize,
- &StringTableCapacity);
- if (!KSUCCESS(Status)) {
- goto WriteBootConfigurationFileEnd;
- }
- Status = BcpAddToStringTable(Context,
- Entry->KernelArguments,
- &(FileEntry->KernelArguments),
- &StringTable,
- &StringTableSize,
- &StringTableCapacity);
- if (!KSUCCESS(Status)) {
- goto WriteBootConfigurationFileEnd;
- }
- Status = BcpAddToStringTable(Context,
- Entry->LoaderPath,
- &(FileEntry->LoaderPath),
- &StringTable,
- &StringTableSize,
- &StringTableCapacity);
- if (!KSUCCESS(Status)) {
- goto WriteBootConfigurationFileEnd;
- }
- Status = BcpAddToStringTable(Context,
- Entry->KernelPath,
- &(FileEntry->KernelPath),
- &StringTable,
- &StringTableSize,
- &StringTableCapacity);
- if (!KSUCCESS(Status)) {
- goto WriteBootConfigurationFileEnd;
- }
- Status = BcpAddToStringTable(Context,
- Entry->SystemPath,
- &(FileEntry->SystemPath),
- &StringTable,
- &StringTableSize,
- &StringTableCapacity);
- if (!KSUCCESS(Status)) {
- goto WriteBootConfigurationFileEnd;
- }
- //
- // If this is the default or boot once entries, fill in the ID now.
- //
- if (Context->GlobalConfiguration.DefaultBootEntry == Entry) {
- Header.DefaultEntry = FileEntry->Id;
- }
- if (Context->GlobalConfiguration.BootOnce == Entry) {
- Header.BootOnce = FileEntry->Id;
- }
- }
- Header.Magic = BOOT_CONFIGURATION_HEADER_MAGIC;
- Header.Version = BOOT_CONFIGURATION_VERSION;
- Header.Key = Context->GlobalConfiguration.Key + 1;
- Header.EntriesOffset = sizeof(BOOT_CONFIGURATION_HEADER);
- Header.EntrySize = sizeof(BOOT_CONFIGURATION_ENTRY);
- Header.EntryCount = Context->BootEntryCount;
- Header.StringsOffset = Header.EntriesOffset +
- (Header.EntrySize * Header.EntryCount);
- Header.StringsSize = StringTableSize;
- Header.TotalSize = Header.StringsOffset + Header.StringsSize;
- Header.Timeout = Context->GlobalConfiguration.Timeout;
- //
- // Allocate and write out the new file data.
- //
- NewFileData = BcAllocate(Context, Header.TotalSize);
- if (NewFileData == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto WriteBootConfigurationFileEnd;
- }
- RtlCopyMemory(NewFileData, &Header, sizeof(BOOT_CONFIGURATION_HEADER));
- RtlCopyMemory(NewFileData + Header.EntriesOffset,
- FileEntries,
- Header.EntrySize * Header.EntryCount);
- RtlCopyMemory(NewFileData + Header.StringsOffset,
- StringTable,
- Header.StringsSize);
- //
- // Compute the CRC32 over the entire buffer.
- //
- FinalHeader = NewFileData;
- FinalHeader->Crc32 = RtlComputeCrc32(0, NewFileData, Header.TotalSize);
- //
- // Free the old file data if there was any, and install this new data.
- //
- if (Context->FileData != NULL) {
- BcFree(Context, Context->FileData);
- }
- Context->FileData = NewFileData;
- Context->FileDataSize = Header.TotalSize;
- NewFileData = NULL;
- Status = STATUS_SUCCESS;
- WriteBootConfigurationFileEnd:
- if (NewFileData != NULL) {
- BcFree(Context, NewFileData);
- }
- if (FileEntries != NULL) {
- BcFree(Context, FileEntries);
- }
- if (StringTable != NULL) {
- BcFree(Context, StringTable);
- }
- return Status;
- }
- KSTATUS
- BcCreateDefaultBootConfiguration (
- PBOOT_CONFIGURATION_CONTEXT Context,
- UCHAR DiskId[BOOT_DISK_ID_SIZE],
- UCHAR PartitionId[BOOT_PARTITION_ID_SIZE]
- )
- /*++
- Routine Description:
- This routine sets up the boot configuration data, creating a single default
- entry.
- Arguments:
- Context - Supplies a pointer to the boot configuration context.
- DiskId - Supplies the disk ID of the boot entry.
- PartitionId - Supplies the partition ID of the boot entry.
- Return Value:
- Returns a pointer to the new boot entry on success.
- NULL on allocation failure.
- --*/
- {
- PBOOT_ENTRY *Entries;
- KSTATUS Status;
- //
- // Create a new boot entry array, and then create a single default boot
- // entry.
- //
- Status = STATUS_INSUFFICIENT_RESOURCES;
- Entries = BcAllocate(Context, sizeof(PVOID));
- if (Entries == NULL) {
- goto CreateDefaultBootConfigurationEnd;
- }
- Entries[0] = BcCreateDefaultBootEntry(Context, NULL, DiskId, PartitionId);
- if (Entries[0] == NULL) {
- goto CreateDefaultBootConfigurationEnd;
- }
- BcpDestroyBootEntries(Context);
- Context->GlobalConfiguration.DefaultBootEntry = Entries[0];
- Context->GlobalConfiguration.BootOnce = NULL;
- Context->GlobalConfiguration.Timeout = BOOT_DEFAULT_TIMEOUT;
- Context->BootEntries = Entries;
- Context->BootEntryCount = 1;
- Entries = NULL;
- Status = STATUS_SUCCESS;
- CreateDefaultBootConfigurationEnd:
- if (Entries != NULL) {
- if (Entries[0] != NULL) {
- BcDestroyBootEntry(Context, Entries[0]);
- }
- BcFree(Context, Entries);
- }
- return Status;
- }
- PBOOT_ENTRY
- BcCreateDefaultBootEntry (
- PBOOT_CONFIGURATION_CONTEXT Context,
- PSTR Name,
- UCHAR DiskId[BOOT_DISK_ID_SIZE],
- UCHAR PartitionId[BOOT_PARTITION_ID_SIZE]
- )
- /*++
- Routine Description:
- This routine creates a new boot entry with the default values.
- Arguments:
- Context - Supplies a pointer to the boot configuration context.
- Name - Supplies an optional pointer to a string containing the name of the
- entry. A copy of this string will be made. If no name is supplied, a
- default name will be used.
- DiskId - Supplies the disk ID of the boot entry.
- PartitionId - Supplies the partition ID of the boot entry.
- Return Value:
- Returns a pointer to the new boot entry on success.
- NULL on allocation failure.
- --*/
- {
- PBOOT_ENTRY Entry;
- KSTATUS Status;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- Entry = BcAllocate(Context, sizeof(BOOT_ENTRY));
- if (Entry == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- RtlZeroMemory(Entry, sizeof(BOOT_ENTRY));
- Entry->Id = 0;
- RtlCopyMemory(Entry->DiskId, DiskId, sizeof(Entry->DiskId));
- RtlCopyMemory(Entry->PartitionId, PartitionId, sizeof(Entry->PartitionId));
- if (Name != NULL) {
- Entry->Name = BcpCopyString(Context, Name);
- } else {
- Entry->Name = BcpCopyString(Context, BOOT_DEFAULT_NAME);
- }
- if (Entry->Name == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- Entry->LoaderPath = BcpCopyString(Context, BOOT_DEFAULT_LOADER_PATH);
- if (Entry->LoaderPath == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- Entry->KernelPath = BcpCopyString(Context, BOOT_DEFAULT_KERNEL_PATH);
- if (Entry->KernelPath == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- Entry->SystemPath = BcpCopyString(Context, BOOT_DEFAULT_SYSTEM_PATH);
- if (Entry->SystemPath == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- Status = STATUS_SUCCESS;
- CreateDefaultBootEntryEnd:
- if (!KSUCCESS(Status)) {
- if (Entry != NULL) {
- BcDestroyBootEntry(Context, Entry);
- Entry = NULL;
- }
- }
- return Entry;
- }
- PBOOT_ENTRY
- BcCopyBootEntry (
- PBOOT_CONFIGURATION_CONTEXT Context,
- PBOOT_ENTRY Source
- )
- /*++
- Routine Description:
- This routine creates a new boot entry based on an existing one.
- Arguments:
- Context - Supplies a pointer to the boot configuration context.
- Source - Supplies a pointer to the boot entry to copy.
- Return Value:
- Returns a pointer to the new boot entry on success.
- NULL on allocation failure.
- --*/
- {
- PBOOT_ENTRY Entry;
- KSTATUS Status;
- PSTR String;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- Entry = BcAllocate(Context, sizeof(BOOT_ENTRY));
- if (Entry == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- RtlZeroMemory(Entry, sizeof(BOOT_ENTRY));
- Entry->Id = Source->Id;
- RtlCopyMemory(Entry->DiskId, Source->DiskId, sizeof(Entry->DiskId));
- RtlCopyMemory(Entry->PartitionId,
- Source->PartitionId,
- sizeof(Entry->PartitionId));
- Entry->Flags = Source->Flags;
- Entry->DebugDevice = Source->DebugDevice;
- String = Source->Name;
- if (String == NULL) {
- String = BOOT_DEFAULT_NAME;
- }
- Entry->Name = BcpCopyString(Context, String);
- if (Entry->Name == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- String = Source->LoaderArguments;
- if (String != NULL) {
- Entry->LoaderArguments = BcpCopyString(Context, String);
- if (Entry->LoaderArguments == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- }
- String = Source->KernelArguments;
- if (String != NULL) {
- Entry->KernelArguments = BcpCopyString(Context, String);
- if (Entry->KernelArguments == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- }
- String = Source->LoaderPath;
- if (String == NULL) {
- String = BOOT_DEFAULT_LOADER_PATH;
- }
- Entry->LoaderPath = BcpCopyString(Context, String);
- if (Entry->LoaderPath == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- String = Source->KernelPath;
- if (String == NULL) {
- String = BOOT_DEFAULT_KERNEL_PATH;
- }
- Entry->KernelPath = BcpCopyString(Context, String);
- if (Entry->KernelPath == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- String = Source->SystemPath;
- if (String == NULL) {
- String = BOOT_DEFAULT_SYSTEM_PATH;
- }
- Entry->SystemPath = BcpCopyString(Context, String);
- if (Entry->SystemPath == NULL) {
- goto CreateDefaultBootEntryEnd;
- }
- Status = STATUS_SUCCESS;
- CreateDefaultBootEntryEnd:
- if (!KSUCCESS(Status)) {
- if (Entry != NULL) {
- BcDestroyBootEntry(Context, Entry);
- Entry = NULL;
- }
- }
- return Entry;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- BcpParseBootEntry (
- PBOOT_CONFIGURATION_CONTEXT Context,
- ULONG EntryIndex,
- PBOOT_ENTRY *Entry
- )
- /*++
- Routine Description:
- This routine parses a single boot entry.
- Arguments:
- Context - Supplies a pointer to the boot configuration context.
- EntryIndex - Supplies the entry number to parse.
- Entry - Supplies a pointer where a pointer to the entry will be returned
- on success.
- Return Value:
- Status code.
- --*/
- {
- PBOOT_CONFIGURATION_ENTRY FileEntry;
- PBOOT_CONFIGURATION_HEADER Header;
- PBOOT_ENTRY NewEntry;
- KSTATUS Status;
- NewEntry = BcAllocate(Context, sizeof(BOOT_ENTRY));
- if (NewEntry == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ParseBootEntryEnd;
- }
- RtlZeroMemory(NewEntry, sizeof(BOOT_ENTRY));
- Header = Context->FileData;
- FileEntry = Context->FileData + Header->EntriesOffset +
- (EntryIndex * Header->EntrySize);
- NewEntry->Id = FileEntry->Id;
- NewEntry->Flags = FileEntry->Flags;
- NewEntry->DebugDevice = FileEntry->DebugDevice;
- RtlCopyMemory(&(NewEntry->DiskId), &(FileEntry->DiskId), BOOT_DISK_ID_SIZE);
- RtlCopyMemory(&(NewEntry->PartitionId),
- &(FileEntry->PartitionId),
- BOOT_PARTITION_ID_SIZE);
- Status = BcpReadString(Context, FileEntry->Name, &(NewEntry->Name));
- if (!KSUCCESS(Status)) {
- goto ParseBootEntryEnd;
- }
- Status = BcpReadString(Context,
- FileEntry->LoaderArguments,
- &(NewEntry->LoaderArguments));
- if (!KSUCCESS(Status)) {
- goto ParseBootEntryEnd;
- }
- Status = BcpReadString(Context,
- FileEntry->KernelArguments,
- &(NewEntry->KernelArguments));
- if (!KSUCCESS(Status)) {
- goto ParseBootEntryEnd;
- }
- Status = BcpReadString(Context,
- FileEntry->LoaderPath,
- &(NewEntry->LoaderPath));
- if (!KSUCCESS(Status)) {
- goto ParseBootEntryEnd;
- }
- Status = BcpReadString(Context,
- FileEntry->KernelPath,
- &(NewEntry->KernelPath));
- if (!KSUCCESS(Status)) {
- goto ParseBootEntryEnd;
- }
- Status = BcpReadString(Context,
- FileEntry->SystemPath,
- &(NewEntry->SystemPath));
- if (!KSUCCESS(Status)) {
- goto ParseBootEntryEnd;
- }
- //
- // If the IDs match for the default boot entry or boot once entry, set
- // those pointers now.
- //
- if (Header->DefaultEntry == FileEntry->Id) {
- Context->GlobalConfiguration.DefaultBootEntry = NewEntry;
- }
- if (Header->BootOnce == FileEntry->Id) {
- Context->GlobalConfiguration.BootOnce = NewEntry;
- }
- Status = STATUS_SUCCESS;
- ParseBootEntryEnd:
- if (!KSUCCESS(Status)) {
- if (NewEntry != NULL) {
- BcDestroyBootEntry(Context, NewEntry);
- NewEntry = NULL;
- }
- }
- *Entry = NewEntry;
- return Status;
- }
- VOID
- BcpDestroyBootEntries (
- PBOOT_CONFIGURATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine destroys the boot entries in the given context.
- Arguments:
- Context - Supplies a pointer to the context.
- Return Value:
- None.
- --*/
- {
- PBOOT_ENTRY Entry;
- ULONG EntryIndex;
- for (EntryIndex = 0;
- EntryIndex < Context->BootEntryCount;
- EntryIndex += 1) {
- Entry = Context->BootEntries[EntryIndex];
- if (Entry != NULL) {
- BcDestroyBootEntry(Context, Entry);
- }
- }
- if (Context->BootEntries != NULL) {
- BcFree(Context, Context->BootEntries);
- }
- Context->BootEntries = NULL;
- Context->BootEntryCount = 0;
- return;
- }
- KSTATUS
- BcpValidateHeader (
- PBOOT_CONFIGURATION_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine performs sanity checks on the boot configuration file to make
- sure it's valid.
- Arguments:
- Context - Supplies a pointer to the context. The file data must be filled
- in.
- Return Value:
- Status code.
- --*/
- {
- ULONG ComputedCrc;
- PBOOT_CONFIGURATION_HEADER Header;
- ULONG HeaderCrc;
- PUCHAR LastCharacter;
- ULONG MaxEntries;
- KSTATUS Status;
- Status = STATUS_FILE_CORRUPT;
- if (Context->FileDataSize < sizeof(BOOT_CONFIGURATION_HEADER)) {
- goto ValidateHeaderEnd;
- }
- //
- // Check that the header is there.
- //
- Header = Context->FileData;
- if ((Header->Magic != BOOT_CONFIGURATION_HEADER_MAGIC) ||
- (Header->TotalSize < sizeof(BOOT_CONFIGURATION_HEADER))) {
- goto ValidateHeaderEnd;
- }
- //
- // Make sure the size reported is at least as big as the data buffer here.
- //
- if (Header->TotalSize > Context->FileDataSize) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ValidateHeaderEnd;
- }
- //
- // Sanity check the offsets.
- //
- if ((Header->EntrySize >= Header->TotalSize) ||
- (Header->EntriesOffset >= Header->TotalSize) ||
- (Header->StringsOffset >= Header->TotalSize) ||
- (Header->StringsSize > Header->TotalSize) ||
- (Header->StringsOffset + Header->StringsSize > Header->TotalSize) ||
- (Header->StringsSize == 0)) {
- goto ValidateHeaderEnd;
- }
- //
- // Perform an estimate on the maximum entries that could possibly fit to
- // weed out multiplication overflow issues below.
- //
- MaxEntries = Header->TotalSize / Header->EntrySize;
- if (Header->EntryCount >= MaxEntries) {
- goto ValidateHeaderEnd;
- }
- //
- // Now that it's at least reasonable, check the actual bounds.
- //
- if ((Header->EntriesOffset + (Header->EntryCount * Header->EntrySize)) >
- Header->TotalSize) {
- goto ValidateHeaderEnd;
- }
- //
- // Ensure the last character of the string table is a terminator.
- //
- LastCharacter = (PUCHAR)Header + Header->StringsOffset +
- Header->StringsSize - 1;
- if (*LastCharacter != '\0') {
- Status = STATUS_INVALID_SEQUENCE;
- goto ValidateHeaderEnd;
- }
- //
- // Compute the CRC of the whole file.
- //
- HeaderCrc = Header->Crc32;
- Header->Crc32 = 0;
- ComputedCrc = RtlComputeCrc32(0, Header, Header->TotalSize);
- Header->Crc32 = HeaderCrc;
- if (ComputedCrc != HeaderCrc) {
- Status = STATUS_CHECKSUM_MISMATCH;
- goto ValidateHeaderEnd;
- }
- //
- // Lookin real good.
- //
- Status = STATUS_SUCCESS;
- ValidateHeaderEnd:
- return Status;
- }
- KSTATUS
- BcpReadString (
- PBOOT_CONFIGURATION_CONTEXT Context,
- ULONG StringOffset,
- PSTR *String
- )
- /*++
- Routine Description:
- This routine reads a string out of the given string table.
- Arguments:
- Context - Supplies a pointer to the boot configuration context.
- StringOffset - Supplies the offset into the string table.
- String - Supplies a pointer where a pointer to a copy of the string will be
- returned on success. The caller is responsible for freeing this memory
- when finished.
- Return Value:
- Status code.
- --*/
- {
- PBOOT_CONFIGURATION_HEADER Header;
- PSTR TableString;
- *String = NULL;
- Header = Context->FileData;
- if (StringOffset >= Header->StringsSize) {
- return STATUS_BUFFER_OVERRUN;
- }
- TableString = Context->FileData + Header->StringsOffset + StringOffset;
- *String = BcpCopyString(Context, TableString);
- if (*String == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- BcpAddToStringTable (
- PBOOT_CONFIGURATION_CONTEXT Context,
- PSTR String,
- PULONG StringIndex,
- PVOID *StringTable,
- PULONG StringTableSize,
- PULONG StringTableCapacity
- )
- /*++
- Routine Description:
- This routine adds a string to the given string table.
- Arguments:
- Context - Supplies a pointer to the boot configuration context.
- String - Supplies a pointer to the string to add.
- StringIndex - Supplies a pointer where the index of the given string in
- the string table will be returned.
- StringTable - Supplies a pointer that on input contains the string table.
- This may get reallocated if the string table needs to expand.
- StringTableSize - Supplies a pointer that on input contains the size of the
- string table in bytes. On output, this value will be updated to contain
- the new size of the string table with this new string added.
- StringTableCapacity - Supplies a pointer that on input contains the size of
- the string table allocation. This may be updated if the string table
- is reallocated.
- Return Value:
- Status code.
- --*/
- {
- ULONG Length;
- PUCHAR NewBuffer;
- ULONG NewCapacity;
- if (String == NULL) {
- String = "";
- }
- Length = RtlStringLength(String);
- //
- // Reallocate if needed.
- //
- if (*StringTableSize + Length + 1 > *StringTableCapacity) {
- if (*StringTableCapacity == 0) {
- NewCapacity = INITIAL_BOOT_CONFIGURATION_STRING_TABLE_SIZE;
- } else {
- NewCapacity = *StringTableCapacity * 2;
- }
- while (NewCapacity < *StringTableSize + Length + 1) {
- ASSERT(NewCapacity * 2 > NewCapacity);
- NewCapacity *= 2;
- }
- NewBuffer = BcAllocate(Context, NewCapacity);
- if (NewBuffer == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- //
- // If the string table is just being created, populate it with the
- // empty string. Otherwise, copy the previous contents over.
- //
- if (*StringTableSize == 0) {
- *NewBuffer = '\0';
- *StringTableSize = 1;
- } else {
- RtlCopyMemory(NewBuffer, *StringTable, *StringTableSize);
- BcFree(Context, *StringTable);
- }
- *StringTableCapacity = NewCapacity;
- *StringTable = NewBuffer;
- }
- //
- // If the length is zero, reuse the empty string. Otherwise, add this
- // onto the end.
- //
- if (Length != 0) {
- *StringIndex = *StringTableSize;
- RtlCopyMemory(*StringTable + *StringTableSize, String, Length + 1);
- *StringTableSize += Length + 1;
- } else {
- *StringIndex = 0;
- }
- return STATUS_SUCCESS;
- }
- PSTR
- BcpCopyString (
- PBOOT_CONFIGURATION_CONTEXT Context,
- PSTR String
- )
- /*++
- Routine Description:
- This routine allocates and copies the given string.
- Arguments:
- Context - Supplies a pointer to the boot configuration context.
- String - Supplies a pointer to the string to copy.
- Return Value:
- Returns a pointer to a newly allocated copy of the given string. The caller
- is responsible for freeing this memory when finished with it.
- NULL on allocation failure.
- --*/
- {
- PSTR Copy;
- UINTN Length;
- Length = RtlStringLength(String);
- Copy = BcAllocate(Context, Length + 1);
- if (Copy == NULL) {
- return NULL;
- }
- RtlCopyMemory(Copy, String, Length + 1);
- return Copy;
- }
|