1210 lines
24 KiB
C++
1210 lines
24 KiB
C++
|
//++
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
//
|
||
|
// blutil.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// This module implements utility functions for the boot loader environment.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
#include "bl.h"
|
||
|
|
||
|
VOID
|
||
|
BlReturnToLegacyMode(
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
BlRtlInitializeListHead(
|
||
|
PLIST_ENTRY Head
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function initializes the specified list head.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Head - Supplies a pointer to the list head to initialize.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
Head->Flink = Head->Blink = Head;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
BlRtlIsListEmpty(
|
||
|
PLIST_ENTRY Head
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function checks if the specified list is empty.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Head - Supplies a pointer to the list head.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if the list is empty.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
return (BOOLEAN) (Head->Flink == Head);
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
BlRtlRemoveEntryList(
|
||
|
PLIST_ENTRY Entry
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function removes the specified entry from the list.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Entry - Supplies a pointer to the entry to remove.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if this was the last entry in the list.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PLIST_ENTRY Blink;
|
||
|
PLIST_ENTRY Flink;
|
||
|
|
||
|
Blink = Entry->Blink;
|
||
|
Flink = Entry->Flink;
|
||
|
|
||
|
BLASSERT(Blink != Entry);
|
||
|
BLASSERT(Flink != Entry);
|
||
|
|
||
|
Blink->Flink = Flink;
|
||
|
Flink->Blink = Blink;
|
||
|
|
||
|
return (BOOLEAN) (Flink == Blink);
|
||
|
}
|
||
|
|
||
|
PLIST_ENTRY
|
||
|
BlRtlRemoveHeadList(
|
||
|
PLIST_ENTRY Head
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function removes an entry from the head of the specified list.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Head - Supplies a pointer to the list to remove from.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// A pointer to the removed entry.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PLIST_ENTRY Entry;
|
||
|
PLIST_ENTRY Flink;
|
||
|
|
||
|
BLASSERT(BlRtlIsListEmpty(Head) == FALSE);
|
||
|
|
||
|
Entry = Head->Flink;
|
||
|
Flink = Entry->Flink;
|
||
|
|
||
|
Head->Flink = Flink;
|
||
|
Flink->Blink = Head;
|
||
|
|
||
|
return Entry;
|
||
|
}
|
||
|
|
||
|
PLIST_ENTRY
|
||
|
BlRtlRemoveTailList(
|
||
|
PLIST_ENTRY Head
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function removes an entry from the tail of the specified list.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Head - Supplies a pointer to the list to remove from.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// A pointer to the removed entry.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PLIST_ENTRY Blink;
|
||
|
PLIST_ENTRY Entry;
|
||
|
|
||
|
BLASSERT(BlRtlIsListEmpty(Head) == FALSE);
|
||
|
|
||
|
Entry = Head->Blink;
|
||
|
Blink = Entry->Blink;
|
||
|
|
||
|
Head->Blink = Blink;
|
||
|
Blink->Flink = Head;
|
||
|
|
||
|
return Entry;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlInsertTailList(
|
||
|
PLIST_ENTRY Head,
|
||
|
PLIST_ENTRY Entry
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function inserts the specified entry to the tail of the specified list.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Head - Supplies a pointer to the list to insert to.
|
||
|
//
|
||
|
// Entry - Supplies a pointer to the entry to insert.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PLIST_ENTRY Blink;
|
||
|
|
||
|
Blink = Head->Blink;
|
||
|
|
||
|
Entry->Flink = Head;
|
||
|
Entry->Blink = Blink;
|
||
|
|
||
|
Head->Blink = Entry;
|
||
|
Blink->Flink = Entry;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlInsertHeadList(
|
||
|
PLIST_ENTRY Head,
|
||
|
PLIST_ENTRY Entry
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function inserts the specified entry to the head of the specified list.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Head - Supplies a pointer to the list to insert to.
|
||
|
//
|
||
|
// Entry - Supplies a pointer to the entry to insert.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PLIST_ENTRY Flink;
|
||
|
|
||
|
Flink = Head->Flink;
|
||
|
|
||
|
Entry->Flink = Flink;
|
||
|
Entry->Blink = Head;
|
||
|
|
||
|
Head->Flink = Entry;
|
||
|
Flink->Blink = Entry;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlConvertLinearPointerToFarPointer(
|
||
|
PVOID LinearPointer,
|
||
|
PFAR_POINTER FarPointer
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function converts the specified linear pointer to a legacy far pointer.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// LinearPointer - Supplies the linear pointer to convert.
|
||
|
//
|
||
|
// FarPointer - Receives the legacy far pointer.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BLASSERT((ULONG_PTR) LinearPointer < LEGACY_MEMORY_LIMIT);
|
||
|
|
||
|
FarPointer->Segment = (UINT16) (((ULONG_PTR) LinearPointer) >> 4);
|
||
|
FarPointer->Offset = (((UINT16) (ULONG_PTR) LinearPointer) & 0xF);
|
||
|
}
|
||
|
|
||
|
PVOID
|
||
|
BlRtlConvertFarPointerToLinearPointer(
|
||
|
PFAR_POINTER FarPointer
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function converts the specified legacy far pointer to a linear pointer.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// FarPointer - Supplies the legacy far pointer to convert.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// Linear pointer matching the specified legacy far pointer.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
|
||
|
return (PVOID) (((ULONG_PTR) FarPointer->Segment << 4) + ((ULONG_PTR) FarPointer->Offset));
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlZeroMemory(
|
||
|
PVOID Buffer,
|
||
|
ULONG_PTR Length
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function zeroes the specified buffer.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Buffer - Supplies a pointer to the buffer to zero.
|
||
|
//
|
||
|
// Length - Supplies the length of the buffer.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PUINT8 Limit;
|
||
|
PUINT8 Next;
|
||
|
|
||
|
Next = (PUINT8) Buffer;
|
||
|
Limit = Next + Length;
|
||
|
|
||
|
while (Next < Limit) {
|
||
|
|
||
|
*Next = 0;
|
||
|
Next += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlCopyMemory(
|
||
|
PVOID Destination,
|
||
|
PCVOID Source,
|
||
|
ULONG_PTR Length
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function copies data from the source buffer to the destination buffer.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Destination - Receives copied data.
|
||
|
//
|
||
|
// Source - Supplies data to copy.
|
||
|
//
|
||
|
// Length - Supplies the length of the data to copy.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
ULONG_PTR DestinationEnd;
|
||
|
ULONG_PTR DestinationStart;
|
||
|
ULONG_PTR Index;
|
||
|
ULONG_PTR SourceEnd;
|
||
|
ULONG_PTR SourceStart;
|
||
|
|
||
|
if (Length == 0) {
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SourceStart = (ULONG_PTR) Source;
|
||
|
SourceEnd = SourceStart + Length;
|
||
|
DestinationStart = (ULONG_PTR) Destination;
|
||
|
DestinationEnd = DestinationStart + Length;
|
||
|
|
||
|
//
|
||
|
// If the higher part of the source buffer intersects with the destination
|
||
|
// buffer, then perform a reverse copy. Otherwise, perform a regular copy.
|
||
|
//
|
||
|
|
||
|
if ((SourceStart < DestinationStart) && (SourceEnd > DestinationStart)) {
|
||
|
|
||
|
Index = Length;
|
||
|
|
||
|
do {
|
||
|
|
||
|
Index -= 1;
|
||
|
|
||
|
((PUINT8) Destination)[Index] = ((PUINT8) Source)[Index];
|
||
|
|
||
|
} while (Index > 0);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
for (Index = 0; Index < Length; Index += 1) {
|
||
|
|
||
|
((PUINT8) Destination)[Index] = ((PUINT8) Source)[Index];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
BlRtlCompareMemory(
|
||
|
PCVOID Buffer1,
|
||
|
PCVOID Buffer2,
|
||
|
ULONG_PTR Length
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function compares the data in the supplied buffers.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Buffer1 - Supplies the first buffer.
|
||
|
//
|
||
|
// Buffer2 - Supplies the second buffer.
|
||
|
//
|
||
|
// Length - Supplies the number of bytes to compare.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if buffers contain identical data.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
ULONG_PTR Index;
|
||
|
|
||
|
for (Index = 0; Index < Length; Index += 1) {
|
||
|
|
||
|
if (((PUINT8) Buffer1)[Index] != ((PUINT8) Buffer2)[Index]) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlMakeLegacyCall(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function switches back to legacy mode, makes the call
|
||
|
// specified in the BEB, and returns back to normal mode.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
//
|
||
|
// Return to legacy mode.
|
||
|
//
|
||
|
|
||
|
BlReturnToLegacyMode();
|
||
|
|
||
|
//
|
||
|
// Re-enable A20 gate -- this is absolutely necessary, because some
|
||
|
// legacy calls (such as some PXE implementations) modify A20 state.
|
||
|
//
|
||
|
|
||
|
BlMmEnableA20Gate();
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlCallLegacyInterruptService(
|
||
|
UINT8 Vector,
|
||
|
PBL_LEGACY_CALL_CONTEXT Input,
|
||
|
PBL_LEGACY_CALL_CONTEXT Output
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function calls the specified legacy interrupt service.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Vector - Supplies the legacy interrupt service vector to call.
|
||
|
//
|
||
|
// Input - Supplies a pointer to the input context for the call.
|
||
|
//
|
||
|
// Output - Supplies a pointer to the output context to fill after the call.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PBEB Beb;
|
||
|
|
||
|
Beb = BlGetBeb();
|
||
|
|
||
|
Beb->LegacyCall_OpCode = LC_INTXX;
|
||
|
Beb->LegacyCall_Vector = Vector;
|
||
|
Beb->LegacyCall_ax = Input->eax;
|
||
|
Beb->LegacyCall_bx = Input->ebx;
|
||
|
Beb->LegacyCall_cx = Input->ecx;
|
||
|
Beb->LegacyCall_dx = Input->edx;
|
||
|
Beb->LegacyCall_si = Input->esi;
|
||
|
Beb->LegacyCall_di = Input->edi;
|
||
|
Beb->LegacyCall_ds = Input->ds;
|
||
|
Beb->LegacyCall_es = Input->es;
|
||
|
|
||
|
BlRtlMakeLegacyCall();
|
||
|
|
||
|
Output->eax = Beb->LegacyCall_ax;
|
||
|
Output->ebx = Beb->LegacyCall_bx;
|
||
|
Output->ecx = Beb->LegacyCall_cx;
|
||
|
Output->edx = Beb->LegacyCall_dx;
|
||
|
Output->esi = Beb->LegacyCall_si;
|
||
|
Output->edi = Beb->LegacyCall_di;
|
||
|
Output->ds = Beb->LegacyCall_ds;
|
||
|
Output->es = Beb->LegacyCall_es;
|
||
|
Output->eflags = Beb->LegacyCall_flags;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlCallLegacyFunction(
|
||
|
UINT16 CodeSegment16,
|
||
|
UINT16 CodeOffset16,
|
||
|
PVOID CallFrame,
|
||
|
UINT32 CallFrameSize,
|
||
|
PBL_LEGACY_CALL_CONTEXT Input,
|
||
|
PBL_LEGACY_CALL_CONTEXT Output
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function calls the specified legacy function.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// CodeSegment16 - Supplies the 16-bit segment value for the function to call.
|
||
|
//
|
||
|
// CodeOffset16 - Supplies the 16-bit offset value for the function to call.
|
||
|
//
|
||
|
// CallFrame - Supplies a pointer to the call frame.
|
||
|
//
|
||
|
// CallFrameSize - Supplies the size of the call frame.
|
||
|
//
|
||
|
// Input - Supplies the input context for the call.
|
||
|
//
|
||
|
// Output - Receives the output context after the call.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
PBEB Beb;
|
||
|
|
||
|
BLASSERT((ULONG_PTR) CallFrame < LEGACY_MEMORY_LIMIT);
|
||
|
|
||
|
BLASSERT(((ULONG_PTR) CallFrame + CallFrameSize) < LEGACY_MEMORY_LIMIT);
|
||
|
|
||
|
Beb = BlGetBeb();
|
||
|
|
||
|
Beb->LegacyCall_OpCode = LC_FARCALL;
|
||
|
Beb->LegacyCall_FuncPtr.Segment = CodeSegment16;
|
||
|
Beb->LegacyCall_FuncPtr.Offset = CodeOffset16;
|
||
|
BlRtlConvertLinearPointerToFarPointer(CallFrame, &Beb->LegacyCall_FramePtr);
|
||
|
Beb->LegacyCall_FrameSize = CallFrameSize;
|
||
|
Beb->LegacyCall_ax = Input->eax;
|
||
|
Beb->LegacyCall_bx = Input->ebx;
|
||
|
Beb->LegacyCall_cx = Input->ecx;
|
||
|
Beb->LegacyCall_dx = Input->edx;
|
||
|
Beb->LegacyCall_si = Input->esi;
|
||
|
Beb->LegacyCall_di = Input->edi;
|
||
|
Beb->LegacyCall_ds = Input->ds;
|
||
|
Beb->LegacyCall_es = Input->es;
|
||
|
|
||
|
BlRtlMakeLegacyCall();
|
||
|
|
||
|
Output->eax = Beb->LegacyCall_ax;
|
||
|
Output->ebx = Beb->LegacyCall_bx;
|
||
|
Output->ecx = Beb->LegacyCall_cx;
|
||
|
Output->edx = Beb->LegacyCall_dx;
|
||
|
Output->esi = Beb->LegacyCall_si;
|
||
|
Output->edi = Beb->LegacyCall_di;
|
||
|
Output->ds = Beb->LegacyCall_ds;
|
||
|
Output->es = Beb->LegacyCall_es;
|
||
|
Output->eflags = Beb->LegacyCall_flags;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlHaltInternal(
|
||
|
PCSTR FileName,
|
||
|
UINT32 LineNumber
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function halts execution.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// FileName - file associated with call site.
|
||
|
//
|
||
|
// LineNumber - line associated with call site.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BlRtlPrintf("BL: Halt! %s(%d)\n", FileName, LineNumber);
|
||
|
|
||
|
for (;;) {
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlAssertFailedPtr(
|
||
|
PCSTR FileName,
|
||
|
UINT32 LineNumber,
|
||
|
ULONG_PTR Param
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function halts execution.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// FileName - file associated with call site.
|
||
|
//
|
||
|
// LineNumber - line associated with call site.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BlRtlPrintf("BL: Assert failed! %s(%d) (%p)\n", FileName, LineNumber, Param);
|
||
|
|
||
|
for (;;) {
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlAssertFailed(
|
||
|
PCSTR FileName,
|
||
|
UINT32 LineNumber
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function halts execution.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// FileName - file associated with call site.
|
||
|
//
|
||
|
// LineNumber - line associated with call site.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BlRtlAssertFailedPtr(FileName, LineNumber, 0);
|
||
|
}
|
||
|
|
||
|
UINT8
|
||
|
BlRtlComputeChecksum8(
|
||
|
PCVOID Buffer,
|
||
|
UINT32 Size
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function computes the 8-bit checksum of the specified buffer.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Buffer - Supplies a pointer to the buffer.
|
||
|
//
|
||
|
// Size - Supplies the size of the buffer.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// 8-bit check sum of the specified buffer.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
UINT8 Checksum;
|
||
|
UINT32 Index;
|
||
|
|
||
|
Checksum = 0;
|
||
|
|
||
|
for (Index = 0; Index < Size; Index += 1) {
|
||
|
|
||
|
Checksum = Checksum + ((PUINT8) Buffer)[Index];
|
||
|
}
|
||
|
|
||
|
return Checksum;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
BlRtlGetDriveParameters(
|
||
|
UINT8 DriveId,
|
||
|
PINT13_DRIVE_PARAMETERS DriveParameters
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function gets the parameters for the specified drive.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// DriveId - Supplies the ID of the drive to query.
|
||
|
//
|
||
|
// DriveParameters - Receives drive parameters.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if query operation was successful.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BL_LEGACY_CALL_CONTEXT Context;
|
||
|
FAR_POINTER FarPointer;
|
||
|
|
||
|
BlRtlZeroMemory(DriveParameters, sizeof(INT13_DRIVE_PARAMETERS));
|
||
|
|
||
|
DriveParameters->StructureSize = sizeof(INT13_DRIVE_PARAMETERS);
|
||
|
|
||
|
BlRtlConvertLinearPointerToFarPointer(DriveParameters, &FarPointer);
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(Context));
|
||
|
|
||
|
Context.eax = 0x4800;
|
||
|
Context.edx = DriveId;
|
||
|
Context.ds = FarPointer.Segment;
|
||
|
Context.esi = FarPointer.Offset;
|
||
|
|
||
|
BlRtlCallLegacyInterruptService(0x13,
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
if (((Context.eflags & RFLAGS_CF) != 0) || ((Context.eax & 0xFF00) != 0)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
#pragma pack(1)
|
||
|
|
||
|
typedef struct _INT13_DISK_ADDRESS_PACKET {
|
||
|
UINT8 PacketSize;
|
||
|
UINT8 Reserved;
|
||
|
UINT16 NumberOfBlocks;
|
||
|
FAR_POINTER Buffer;
|
||
|
UINT64 FirstBlock;
|
||
|
} INT13_DISK_ADDRESS_PACKET, *PINT13_DISK_ADDRESS_PACKET;
|
||
|
|
||
|
C_ASSERT(sizeof(INT13_DISK_ADDRESS_PACKET) == 0x10);
|
||
|
|
||
|
#pragma pack()
|
||
|
|
||
|
INT13_DISK_ADDRESS_PACKET BlInt13AddressPacket;
|
||
|
|
||
|
BOOLEAN
|
||
|
BlRtlReadDrive(
|
||
|
UINT8 DriveId,
|
||
|
UINT64 FirstBlock,
|
||
|
UINT16 NumberOfBlocks,
|
||
|
PVOID Buffer
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function reads from the specified drive region.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// DriveId - Supplies the ID of the drive to read from.
|
||
|
//
|
||
|
// FirstBlock - Supplies the first block to read.
|
||
|
//
|
||
|
// NumberOfBlocks - Supplies the number of blocks to read.
|
||
|
//
|
||
|
// Buffer - Receives data.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if read operation was successful.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
FAR_POINTER AddressPacketPointer;
|
||
|
BL_LEGACY_CALL_CONTEXT Context;
|
||
|
|
||
|
BlRtlZeroMemory(&BlInt13AddressPacket, sizeof(BlInt13AddressPacket));
|
||
|
BlRtlZeroMemory(&Context, sizeof(Context));
|
||
|
|
||
|
BLASSERT(((ULONG_PTR) &BlInt13AddressPacket) < LEGACY_MEMORY_LIMIT);
|
||
|
BLASSERT((ULONG_PTR) Buffer < LEGACY_MEMORY_LIMIT);
|
||
|
|
||
|
BlInt13AddressPacket.PacketSize = sizeof(BlInt13AddressPacket);
|
||
|
BlInt13AddressPacket.FirstBlock = FirstBlock;
|
||
|
BlInt13AddressPacket.NumberOfBlocks = NumberOfBlocks;
|
||
|
BlRtlConvertLinearPointerToFarPointer(Buffer, &BlInt13AddressPacket.Buffer);
|
||
|
|
||
|
BlRtlConvertLinearPointerToFarPointer(&BlInt13AddressPacket, &AddressPacketPointer);
|
||
|
|
||
|
Context.eax = 0x4200;
|
||
|
Context.edx = DriveId;
|
||
|
Context.ds = AddressPacketPointer.Segment;
|
||
|
Context.esi = AddressPacketPointer.Offset;
|
||
|
|
||
|
BlRtlCallLegacyInterruptService(0x13,
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
if (((Context.eflags & RFLAGS_CF) != 0) || ((Context.eax & 0xFF00) != 0)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
(*BlFsGetFileSize)(
|
||
|
PCSTR Path,
|
||
|
PUINT32 FileSize
|
||
|
);
|
||
|
|
||
|
BOOLEAN
|
||
|
(*BlFsReadFile)(
|
||
|
PCSTR Path,
|
||
|
PVOID Buffer,
|
||
|
UINT32 NumberOfBytes
|
||
|
);
|
||
|
|
||
|
#define CMOS_CONTROL_REGISTER 0x0070
|
||
|
#define CMOS_DATA_REGISTER 0x0071
|
||
|
|
||
|
#define CMOS_SECONDS_REGISTER 0x00
|
||
|
#define CMOS_MINUTES_REGISTER 0x02
|
||
|
#define CMOS_HOURS_REGISTER 0x04
|
||
|
#define CMOS_DAYS_REGISTER 0x07
|
||
|
#define CMOS_MONTHS_REGISTER 0x08
|
||
|
#define CMOS_YEARS_REGISTER 0x09
|
||
|
#define CMOS_STATUS_REGISTER_A 0x0A
|
||
|
#define CMOS_STATUS_REGISTER_B 0x0B
|
||
|
#define CMOS_SHUTDOWN_REGISTER 0x0F
|
||
|
|
||
|
#define CMOS_CLOCK_IN_BINARY 0x04
|
||
|
#define CMOS_ENABLE_PERIODIC_TIMER 0x40
|
||
|
#define CMOS_RATE_MASK 0x0F
|
||
|
#define CMOS_DEFAULT_RATE 0x06
|
||
|
|
||
|
UINT8
|
||
|
BlCmosReadRegister(
|
||
|
UINT8 Register
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function reads from the specified CMOS register.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Register - Supplies the CMOS register to read from.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// Value read from the specified CMOS register.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BlRtlWritePort8(CMOS_CONTROL_REGISTER, Register);
|
||
|
|
||
|
return BlRtlReadPort8(CMOS_DATA_REGISTER);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlCmosWriteRegister(
|
||
|
UINT8 Register,
|
||
|
UINT8 Value
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function writes to the specified CMOS register.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Register - Supplies the CMOS register to write to.
|
||
|
//
|
||
|
// Value - Supplies the value to write.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BlRtlWritePort8(CMOS_CONTROL_REGISTER, Register);
|
||
|
|
||
|
BlRtlWritePort8(CMOS_DATA_REGISTER, Value);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlResetSystem(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function resets the system.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BL_LEGACY_CALL_CONTEXT Context;
|
||
|
UINT8 Value;
|
||
|
|
||
|
//
|
||
|
// Issue a no-op legacy operation to restore legacy context.
|
||
|
//
|
||
|
|
||
|
BlGetBeb()->LegacyCall_OpCode = LC_NOP;
|
||
|
BlRtlMakeLegacyCall();
|
||
|
|
||
|
//
|
||
|
// Disable periodic interrupt.
|
||
|
//
|
||
|
|
||
|
Value = BlCmosReadRegister(CMOS_STATUS_REGISTER_B);
|
||
|
Value &= ~CMOS_ENABLE_PERIODIC_TIMER;
|
||
|
BlCmosWriteRegister(CMOS_STATUS_REGISTER_B, Value);
|
||
|
|
||
|
//
|
||
|
// Set default rate.
|
||
|
//
|
||
|
|
||
|
Value = BlCmosReadRegister(CMOS_STATUS_REGISTER_A);
|
||
|
Value &= ~CMOS_RATE_MASK;
|
||
|
Value |= CMOS_DEFAULT_RATE;
|
||
|
BlCmosWriteRegister(CMOS_STATUS_REGISTER_A, Value);
|
||
|
|
||
|
//
|
||
|
// Set reset reason.
|
||
|
//
|
||
|
|
||
|
BlCmosWriteRegister(CMOS_SHUTDOWN_REGISTER, 0);
|
||
|
|
||
|
//
|
||
|
// Try to reset using ACPI.
|
||
|
//
|
||
|
|
||
|
BlRtlPrintf("BL: Attempting reset with ACPI.\n");
|
||
|
|
||
|
BlAcpiResetSystem();
|
||
|
|
||
|
//
|
||
|
// If the ACPI call returned, then it indicates that ACPI reset is
|
||
|
// not supported, so try to reset with the keyboard controller.
|
||
|
//
|
||
|
|
||
|
BlRtlPrintf("BL: Attempting reset with keyboard controller.\n");
|
||
|
|
||
|
BL_KEYBOARD_WRITE_COMMAND(BL_KEYBOARD_COMMAND_PULSE_RESET_BIT);
|
||
|
|
||
|
//
|
||
|
// Issue INT19 as last resort.
|
||
|
//
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(Context));
|
||
|
|
||
|
BlRtlCallLegacyInterruptService(0x19,
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlShutdownSystem(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function shuts down the system.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BL_LEGACY_CALL_CONTEXT Context;
|
||
|
UINT32 Index;
|
||
|
|
||
|
//
|
||
|
// AIFIX: Add ACPI shutdown logic here.
|
||
|
//
|
||
|
|
||
|
BlRtlPrintf("BL: Attempting system shutdown through APM.\n");
|
||
|
|
||
|
//
|
||
|
// APM installation check.
|
||
|
//
|
||
|
|
||
|
#if APM_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("APM: INT15/5300h [Installation Check]\n");
|
||
|
|
||
|
#endif
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(Context));
|
||
|
|
||
|
Context.eax = 0x5300;
|
||
|
|
||
|
BlRtlCallLegacyInterruptService(0x15,
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
if (((Context.eflags & RFLAGS_CF) != 0) || (Context.ebx != 0x504D)) {
|
||
|
|
||
|
BlRtlPrintf("APM: Not available!\n");
|
||
|
BlRtlHalt();
|
||
|
}
|
||
|
|
||
|
#if APM_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("APM: Found APM v%u.%u.\n",
|
||
|
(Context.eax >> 8) & 0xFF,
|
||
|
Context.eax && 0xFF);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Connect real-mode interface.
|
||
|
//
|
||
|
|
||
|
#if APM_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("APM: INT15/5301h [Connect Real-Mode Interface]\n");
|
||
|
|
||
|
#endif
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(Context));
|
||
|
|
||
|
Context.eax = 0x5301;
|
||
|
|
||
|
BlRtlCallLegacyInterruptService(0x15,
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
if ((Context.eflags & RFLAGS_CF) != 0) {
|
||
|
|
||
|
BlRtlPrintf("APM: INT15/5301h failed!\n");
|
||
|
BlRtlHalt();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set APM driver version.
|
||
|
//
|
||
|
|
||
|
#if APM_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("APM: INT15/530Eh [Set APM Driver Version]\n");
|
||
|
|
||
|
#endif
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(Context));
|
||
|
|
||
|
Context.eax = 0x530E;
|
||
|
Context.ecx = 0x0102;
|
||
|
|
||
|
BlRtlCallLegacyInterruptService(0x15,
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
if ((Context.eflags & RFLAGS_CF) != 0) {
|
||
|
|
||
|
BlRtlPrintf("APM: INT15/530Eh failed!\n");
|
||
|
BlRtlHalt();
|
||
|
}
|
||
|
|
||
|
#if APM_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("APM: INT15/5307h [Shutdown]\n");
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Announce shutdown.
|
||
|
//
|
||
|
// Note that the lab infrastructure searches for this string
|
||
|
// when attempting to determine if the host successfully
|
||
|
// reached shutdown.
|
||
|
//
|
||
|
|
||
|
BlRtlPrintf("APM: Power-off via APM.\n");
|
||
|
|
||
|
//
|
||
|
// Issue APM shutdown command.
|
||
|
//
|
||
|
|
||
|
Context.eax = 0x5307;
|
||
|
Context.ebx = 1;
|
||
|
Context.ecx = 3;
|
||
|
|
||
|
BlRtlCallLegacyInterruptService(0x15,
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UINT8
|
||
|
BlRtlConvertBcdToBinary8(
|
||
|
UINT8 BcdValue
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function converts the specified 8-bit BCD value to binary.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// BcdValue - Supplies the BCD value to convert.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// Binary value matching the specified BCD value.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
return (((BcdValue >> 4) & 0xF) * 10) + (BcdValue & 0xF);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlRtlGetCurrentTime(
|
||
|
PBL_TIME Time
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function queries the current time.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Time - Receives current time.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
//
|
||
|
// Query CMOS RTC.
|
||
|
//
|
||
|
|
||
|
Time->Year = BlCmosReadRegister(CMOS_YEARS_REGISTER);
|
||
|
Time->Month = BlCmosReadRegister(CMOS_MONTHS_REGISTER);
|
||
|
Time->Day = BlCmosReadRegister(CMOS_DAYS_REGISTER);
|
||
|
Time->Hour = BlCmosReadRegister(CMOS_HOURS_REGISTER);
|
||
|
Time->Minute = BlCmosReadRegister(CMOS_MINUTES_REGISTER);
|
||
|
Time->Second = BlCmosReadRegister(CMOS_SECONDS_REGISTER);
|
||
|
|
||
|
//
|
||
|
// If the clock is in BCD format, then convert it to binary.
|
||
|
//
|
||
|
|
||
|
if ((BlCmosReadRegister(CMOS_STATUS_REGISTER_B) & CMOS_CLOCK_IN_BINARY) == 0) {
|
||
|
|
||
|
Time->Year = BlRtlConvertBcdToBinary8((UINT8) Time->Year);
|
||
|
Time->Month = BlRtlConvertBcdToBinary8(Time->Month);
|
||
|
Time->Day = BlRtlConvertBcdToBinary8(Time->Day);
|
||
|
Time->Hour = BlRtlConvertBcdToBinary8(Time->Hour);
|
||
|
Time->Minute = BlRtlConvertBcdToBinary8(Time->Minute);
|
||
|
Time->Second = BlRtlConvertBcdToBinary8(Time->Second);
|
||
|
}
|
||
|
}
|
||
|
|