2006-11-15 00:08:51 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS HAL
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
2006-11-29 08:28:20 +00:00
|
|
|
* FILE: hal/halx86/generic/halinit.c
|
|
|
|
* PURPOSE: HAL Entrypoint and Initialization
|
2006-11-15 00:08:51 +00:00
|
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
2001-08-21 20:18:27 +00:00
|
|
|
*/
|
|
|
|
|
2006-11-15 00:08:51 +00:00
|
|
|
/* INCLUDES ******************************************************************/
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2005-06-18 14:29:31 +00:00
|
|
|
#include <hal.h>
|
2005-06-19 22:53:49 +00:00
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2006-11-15 00:08:51 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
2004-03-18 19:58:35 +00:00
|
|
|
|
2010-03-31 04:38:20 +00:00
|
|
|
/* Share with Mm headers? */
|
|
|
|
#define MM_HAL_VA_START (PVOID)0xFFC00000
|
|
|
|
#define MM_HAL_HEAP_START (PVOID)((ULONG_PTR)MM_HAL_VA_START + (1024 * 1024))
|
|
|
|
|
2006-11-27 19:26:31 +00:00
|
|
|
BOOLEAN HalpPciLockSettings;
|
2010-03-31 04:38:20 +00:00
|
|
|
ULONG HalpUsedAllocDescriptors;
|
|
|
|
MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray[64];
|
|
|
|
PVOID HalpHeapStart = MM_HAL_HEAP_START;
|
2006-11-27 19:26:31 +00:00
|
|
|
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
|
2010-03-31 04:38:20 +00:00
|
|
|
ULONG
|
|
|
|
NTAPI
|
|
|
|
HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
|
|
IN ULONG MaxAddress,
|
|
|
|
IN ULONG PageCount,
|
|
|
|
IN BOOLEAN Aligned)
|
|
|
|
{
|
|
|
|
ULONG UsedDescriptors, Alignment, PhysicalAddress;
|
|
|
|
PFN_NUMBER MaxPage, BasePage;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
PMEMORY_ALLOCATION_DESCRIPTOR MdBlock, NewBlock, FreeBlock;
|
|
|
|
|
|
|
|
/* Highest page we'll go */
|
|
|
|
MaxPage = MaxAddress >> PAGE_SHIFT;
|
|
|
|
|
|
|
|
/* We need at least two blocks */
|
|
|
|
if ((HalpUsedAllocDescriptors + 2) > 64) return 0;
|
|
|
|
|
|
|
|
/* Remember how many we have now */
|
|
|
|
UsedDescriptors = HalpUsedAllocDescriptors;
|
|
|
|
|
|
|
|
/* Loop the loader block memory descriptors */
|
|
|
|
NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
|
|
|
|
while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
|
|
|
|
{
|
|
|
|
/* Get the block */
|
|
|
|
MdBlock = CONTAINING_RECORD(NextEntry,
|
|
|
|
MEMORY_ALLOCATION_DESCRIPTOR,
|
|
|
|
ListEntry);
|
|
|
|
|
|
|
|
/* No alignment by default */
|
|
|
|
Alignment = 0;
|
|
|
|
|
|
|
|
/* Unless requested, in which case we use a 64KB block alignment */
|
|
|
|
if (Aligned) Alignment = ((MdBlock->BasePage + 0x0F) & ~0x0F) - MdBlock->BasePage;
|
|
|
|
|
|
|
|
/* Search for free memory */
|
|
|
|
if ((MdBlock->MemoryType == LoaderFree) ||
|
|
|
|
(MdBlock->MemoryType == MemoryFirmwareTemporary))
|
|
|
|
{
|
|
|
|
/* Make sure the page is within bounds, including alignment */
|
|
|
|
BasePage = MdBlock->BasePage;
|
|
|
|
if ((BasePage) &&
|
|
|
|
(MdBlock->PageCount >= PageCount + Alignment) &&
|
|
|
|
(BasePage + PageCount + Alignment < MaxPage))
|
|
|
|
{
|
|
|
|
|
|
|
|
/* We found an address */
|
|
|
|
PhysicalAddress = (BasePage + Alignment) << PAGE_SHIFT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Keep trying */
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we didn't find anything, get out of here */
|
|
|
|
if (NextEntry == &LoaderBlock->MemoryDescriptorListHead) return 0;
|
|
|
|
|
|
|
|
/* Okay, now get a descriptor */
|
|
|
|
NewBlock = &HalpAllocationDescriptorArray[HalpUsedAllocDescriptors];
|
|
|
|
NewBlock->PageCount = PageCount;
|
|
|
|
NewBlock->BasePage = MdBlock->BasePage + Alignment;
|
|
|
|
NewBlock->MemoryType = LoaderHALCachedMemory;
|
|
|
|
|
|
|
|
/* Update count */
|
|
|
|
UsedDescriptors++;
|
|
|
|
HalpUsedAllocDescriptors = UsedDescriptors;
|
|
|
|
|
|
|
|
/* Check if we had any alignment */
|
|
|
|
if (Alignment)
|
|
|
|
{
|
|
|
|
/* Check if we had leftovers */
|
|
|
|
if ((MdBlock->PageCount - Alignment) != PageCount)
|
|
|
|
{
|
|
|
|
/* Get the next descriptor */
|
|
|
|
FreeBlock = &HalpAllocationDescriptorArray[UsedDescriptors];
|
|
|
|
FreeBlock->PageCount = MdBlock->PageCount - Alignment - PageCount;
|
|
|
|
FreeBlock->BasePage = MdBlock->BasePage + Alignment + PageCount;
|
|
|
|
|
|
|
|
/* One more */
|
|
|
|
HalpUsedAllocDescriptors++;
|
|
|
|
|
|
|
|
/* Insert it into the list */
|
|
|
|
InsertHeadList(&MdBlock->ListEntry, &FreeBlock->ListEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use this descriptor */
|
|
|
|
NewBlock->PageCount = Alignment;
|
|
|
|
InsertHeadList(&MdBlock->ListEntry, &NewBlock->ListEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Consume memory from this block */
|
|
|
|
MdBlock->BasePage += PageCount;
|
|
|
|
MdBlock->PageCount -= PageCount;
|
|
|
|
|
|
|
|
/* Insert the descriptor */
|
|
|
|
InsertTailList(&MdBlock->ListEntry, &NewBlock->ListEntry);
|
|
|
|
|
|
|
|
/* Remove the entry if the whole block was allocated */
|
|
|
|
if (!MdBlock->PageCount == 0) RemoveEntryList(&MdBlock->ListEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the address */
|
|
|
|
return PhysicalAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
PVOID
|
|
|
|
NTAPI
|
|
|
|
HalpMapPhysicalMemory64(IN PHYSICAL_ADDRESS PhysicalAddress,
|
|
|
|
IN ULONG PageCount)
|
|
|
|
{
|
|
|
|
PHARDWARE_PTE PointerPte;
|
|
|
|
ULONG UsedPages = 0;
|
|
|
|
PVOID VirtualAddress, BaseAddress;
|
|
|
|
|
|
|
|
/* Start at the current HAL heap base */
|
|
|
|
BaseAddress = HalpHeapStart;
|
|
|
|
|
|
|
|
/* Loop until we have all the pages required */
|
|
|
|
while (UsedPages < PageCount)
|
|
|
|
{
|
|
|
|
/* Begin a new loop cycle */
|
|
|
|
UsedPages = 0;
|
|
|
|
VirtualAddress = BaseAddress;
|
|
|
|
|
|
|
|
/* If this overflows past the HAL heap, it means there's no space */
|
|
|
|
if (BaseAddress == NULL) return NULL;
|
|
|
|
|
|
|
|
/* Loop until we have all the pages required in a single run */
|
|
|
|
while (UsedPages < PageCount)
|
|
|
|
{
|
|
|
|
/* Get the PTE for this address and check if it's available */
|
|
|
|
PointerPte = HalAddressToPte(VirtualAddress);
|
|
|
|
if (*(PULONG)PointerPte)
|
|
|
|
{
|
|
|
|
/* PTE has data, skip it and start with a new base address */
|
|
|
|
BaseAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PTE is available, keep going on this run */
|
|
|
|
VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
|
|
|
|
UsedPages++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Take the base address of the page plus the actual offset in the address */
|
|
|
|
VirtualAddress = (PVOID)((ULONG_PTR)BaseAddress +
|
|
|
|
BYTE_OFFSET(PhysicalAddress.LowPart));
|
|
|
|
|
|
|
|
/* If we are starting at the heap, move the heap */
|
|
|
|
if (BaseAddress == HalpHeapStart)
|
|
|
|
{
|
|
|
|
/* Past this allocation */
|
|
|
|
HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop pages that can be mapped */
|
|
|
|
while (UsedPages--)
|
|
|
|
{
|
|
|
|
/* Fill out the PTE */
|
|
|
|
PointerPte = HalAddressToPte(BaseAddress);
|
|
|
|
PointerPte->PageFrameNumber = PhysicalAddress.QuadPart >> PAGE_SHIFT;
|
|
|
|
PointerPte->Valid = 1;
|
|
|
|
PointerPte->Write = 1;
|
|
|
|
|
|
|
|
/* Move to the next address */
|
|
|
|
PhysicalAddress.QuadPart += PAGE_SIZE;
|
|
|
|
BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Flush the TLB and return the address */
|
|
|
|
HalpFlushTLB();
|
|
|
|
return VirtualAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
HalpUnmapVirtualAddress(IN PVOID VirtualAddress,
|
|
|
|
IN ULONG PageCount)
|
|
|
|
{
|
|
|
|
PHARDWARE_PTE PointerPte;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
/* Only accept valid addresses */
|
|
|
|
if (VirtualAddress < MM_HAL_VA_START) return;
|
|
|
|
|
|
|
|
/* Align it down to page size */
|
|
|
|
VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1));
|
|
|
|
|
|
|
|
/* Loop PTEs */
|
|
|
|
PointerPte = HalAddressToPte(VirtualAddress);
|
|
|
|
for (i = 0; i < PageCount; i++)
|
|
|
|
{
|
|
|
|
*(PULONG)PointerPte = 0;
|
|
|
|
PointerPte++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Flush the TLB */
|
|
|
|
HalpFlushTLB();
|
|
|
|
|
|
|
|
/* Put the heap back */
|
|
|
|
if (HalpHeapStart > VirtualAddress) HalpHeapStart = VirtualAddress;
|
|
|
|
}
|
|
|
|
|
2006-11-27 19:26:31 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
HalpGetParameters(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
|
|
{
|
|
|
|
PCHAR CommandLine;
|
|
|
|
|
|
|
|
/* Make sure we have a loader block and command line */
|
|
|
|
if ((LoaderBlock) && (LoaderBlock->LoadOptions))
|
|
|
|
{
|
|
|
|
/* Read the command line */
|
|
|
|
CommandLine = LoaderBlock->LoadOptions;
|
|
|
|
|
|
|
|
/* Check if PCI is locked */
|
|
|
|
if (strstr(CommandLine, "PCILOCK")) HalpPciLockSettings = TRUE;
|
|
|
|
|
|
|
|
/* Check for initial breakpoint */
|
|
|
|
if (strstr(CommandLine, "BREAK")) DbgBreakPoint();
|
|
|
|
}
|
|
|
|
}
|
2004-03-18 19:58:35 +00:00
|
|
|
|
2006-11-15 00:08:51 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2006-11-15 00:08:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
HalInitSystem(IN ULONG BootPhase,
|
|
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2006-11-27 19:26:31 +00:00
|
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2006-11-27 19:26:31 +00:00
|
|
|
/* Check the boot phase */
|
|
|
|
if (!BootPhase)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2006-11-27 19:26:31 +00:00
|
|
|
/* Phase 0... save bus type */
|
|
|
|
HalpBusType = LoaderBlock->u.I386.MachineType & 0xFF;
|
|
|
|
|
|
|
|
/* Get command-line parameters */
|
|
|
|
HalpGetParameters(LoaderBlock);
|
|
|
|
|
|
|
|
/* Checked HAL requires checked kernel */
|
|
|
|
#if DBG
|
|
|
|
if (!(Prcb->BuildType & PRCB_BUILD_DEBUG))
|
|
|
|
{
|
|
|
|
/* No match, bugcheck */
|
|
|
|
KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 1, 0);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/* Release build requires release HAL */
|
|
|
|
if (Prcb->BuildType & PRCB_BUILD_DEBUG)
|
|
|
|
{
|
|
|
|
/* No match, bugcheck */
|
|
|
|
KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/* SMP HAL requires SMP kernel */
|
|
|
|
if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR)
|
|
|
|
{
|
|
|
|
/* No match, bugcheck */
|
|
|
|
KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Validate the PRCB */
|
|
|
|
if (Prcb->MajorVersion != PRCB_MAJOR_VERSION)
|
|
|
|
{
|
|
|
|
/* Validation failed, bugcheck */
|
|
|
|
KeBugCheckEx(MISMATCHED_HAL, 1, Prcb->MajorVersion, 1, 0);
|
|
|
|
}
|
|
|
|
|
2010-03-03 21:56:52 +00:00
|
|
|
#ifndef _MINIHAL_
|
2010-03-31 04:43:39 +00:00
|
|
|
/* Initialize ACPI */
|
|
|
|
HalpSetupAcpiPhase0(LoaderBlock);
|
|
|
|
|
2006-11-29 08:28:20 +00:00
|
|
|
/* Initialize the PICs */
|
2010-01-21 12:51:13 +00:00
|
|
|
HalpInitializePICs(TRUE);
|
2010-03-03 21:56:52 +00:00
|
|
|
#endif
|
2006-11-29 08:28:20 +00:00
|
|
|
|
|
|
|
/* Force initial PIC state */
|
|
|
|
KfRaiseIrql(KeGetCurrentIrql());
|
|
|
|
|
2009-10-29 19:58:41 +00:00
|
|
|
/* Initialize CMOS lock */
|
|
|
|
KeInitializeSpinLock(&HalpSystemHardwareLock);
|
2006-11-27 19:26:31 +00:00
|
|
|
|
2009-10-29 19:58:41 +00:00
|
|
|
/* Initialize CMOS */
|
|
|
|
HalpInitializeCmos();
|
2009-10-27 01:03:41 +00:00
|
|
|
|
2006-11-27 19:26:31 +00:00
|
|
|
/* Fill out the dispatch tables */
|
|
|
|
HalQuerySystemInformation = HaliQuerySystemInformation;
|
|
|
|
HalSetSystemInformation = HaliSetSystemInformation;
|
|
|
|
HalInitPnpDriver = NULL; // FIXME: TODO
|
2010-03-03 21:56:52 +00:00
|
|
|
#ifndef _MINIHAL_
|
2006-11-27 19:26:31 +00:00
|
|
|
HalGetDmaAdapter = HalpGetDmaAdapter;
|
2010-03-03 21:56:52 +00:00
|
|
|
#else
|
|
|
|
HalGetDmaAdapter = NULL;
|
|
|
|
#endif
|
2006-11-27 19:26:31 +00:00
|
|
|
HalGetInterruptTranslator = NULL; // FIXME: TODO
|
2010-03-03 21:56:52 +00:00
|
|
|
#ifndef _MINIHAL_
|
2007-12-15 17:15:48 +00:00
|
|
|
HalResetDisplay = HalpBiosDisplayReset;
|
2010-03-03 21:56:52 +00:00
|
|
|
#else
|
|
|
|
HalResetDisplay = NULL;
|
|
|
|
#endif
|
- Stub out DbgKdWriteVirtualMemoryApi, DbgKdReadPhysicalMemoryApi, DbgKdWritePhysicalMemoryApi, DbgKdWriteBreakPointExApi, DbgKdRestoreBreakPointExApi, DbgKdSearchMemoryApi and DbgKdFillMemoryApi cases more properly.
- Fail on physical memory write like we do for read too.
- Don't handle OldVlm1/2 as they appear to be deprecated and unhandled in Windows.
- Implement HalHaltSystem to halt execution in a portable way. Default to xHalHaltSystem, a simple infinite loop, if we get called before HAL has initialized. Use this in KiBugCheckDebugBreak and the system shutdown handler instead of x86/AMD64/ARM intrinsics.
- Don't try to halt the CPU if KeBugCheck has been called 3 times or more -- if this happens, something has gone very wrong, and we shouldn't try to do anything special. Just loop infinitely.
- Fix KiBugCheckDebugBreak -- it shouldn't halt execution when called for the first chance as bugcheck callbacks have not been invoked at this point (nor has the BSOD been displayed). Use SEH to protect against a crash instead of checking KdDebuggerNotPresent as the debugger, if it is present, *could* disconnect while the trap is being handled. Also, don't halt execution if the debugger handled the breakpoint, just break again.
- Don't call MmMapIoSpace from HalpReboot! The reboot might take place at elevated IRQL (as high as HIGH_LEVEL if called from KeBugCheck), and thus can't use any Mm support routines. Use a PTE from the reserved HAL region and map it ourselves instead as done in the BIOS call code.
- Acquire the display ownership in HalReturnToFirmware in case the caller hasn't done so (as done in the KD reboot routine, for example).
- Just include ntndk.h in hal.h instead of including 6 NDK headers (which turns into more than half of the NDK anyway since those headers include other NDK headers).
- Crashing and rebooting from KD now works properly.
svn path=/trunk/; revision=43380
2009-10-11 20:16:45 +00:00
|
|
|
HalHaltSystem = HaliHaltSystem;
|
2006-11-27 19:26:31 +00:00
|
|
|
|
2009-10-29 19:58:41 +00:00
|
|
|
/* Register IRQ 2 */
|
|
|
|
HalpRegisterVector(IDT_INTERNAL,
|
|
|
|
PRIMARY_VECTOR_BASE + 2,
|
|
|
|
PRIMARY_VECTOR_BASE + 2,
|
|
|
|
HIGH_LEVEL);
|
|
|
|
|
|
|
|
/* Setup I/O space */
|
|
|
|
HalpDefaultIoSpace.Next = HalpAddressUsageList;
|
|
|
|
HalpAddressUsageList = &HalpDefaultIoSpace;
|
|
|
|
|
|
|
|
/* Setup busy waiting */
|
|
|
|
HalpCalibrateStallExecution();
|
|
|
|
|
2010-03-03 21:56:52 +00:00
|
|
|
#ifndef _MINIHAL_
|
2009-10-29 19:58:41 +00:00
|
|
|
/* Initialize the clock */
|
|
|
|
HalpInitializeClock();
|
2010-03-03 21:56:52 +00:00
|
|
|
#endif
|
2009-10-29 19:58:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We could be rebooting with a pending profile interrupt,
|
|
|
|
* so clear it here before interrupts are enabled
|
|
|
|
*/
|
|
|
|
HalStopProfileInterrupt(ProfileTime);
|
2007-12-13 15:44:17 +00:00
|
|
|
|
|
|
|
/* Do some HAL-specific initialization */
|
|
|
|
HalpInitPhase0(LoaderBlock);
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|
2006-11-15 00:08:51 +00:00
|
|
|
else if (BootPhase == 1)
|
2001-08-21 20:18:27 +00:00
|
|
|
{
|
2009-11-09 22:59:49 +00:00
|
|
|
/* Initialize bus handlers */
|
|
|
|
HalpInitBusHandler();
|
2006-11-27 19:26:31 +00:00
|
|
|
|
2010-03-03 21:56:52 +00:00
|
|
|
#ifndef _MINIHAL_
|
2009-10-29 19:58:41 +00:00
|
|
|
/* Enable IRQ 0 */
|
|
|
|
HalpEnableInterruptHandler(IDT_DEVICE,
|
|
|
|
0,
|
|
|
|
PRIMARY_VECTOR_BASE,
|
|
|
|
CLOCK2_LEVEL,
|
|
|
|
HalpClockInterrupt,
|
|
|
|
Latched);
|
|
|
|
|
|
|
|
/* Enable IRQ 8 */
|
|
|
|
HalpEnableInterruptHandler(IDT_DEVICE,
|
|
|
|
0,
|
|
|
|
PRIMARY_VECTOR_BASE + 8,
|
|
|
|
PROFILE_LEVEL,
|
|
|
|
HalpProfileInterrupt,
|
|
|
|
Latched);
|
2006-11-15 00:08:51 +00:00
|
|
|
|
2006-11-27 19:26:31 +00:00
|
|
|
/* Initialize DMA. NT does this in Phase 0 */
|
2006-11-15 00:08:51 +00:00
|
|
|
HalpInitDma();
|
2010-03-03 21:56:52 +00:00
|
|
|
#endif
|
2007-12-13 15:44:17 +00:00
|
|
|
|
|
|
|
/* Do some HAL-specific initialization */
|
|
|
|
HalpInitPhase1();
|
2006-11-15 00:08:51 +00:00
|
|
|
}
|
2001-08-21 20:18:27 +00:00
|
|
|
|
2006-11-15 00:08:51 +00:00
|
|
|
/* All done, return */
|
|
|
|
return TRUE;
|
2001-08-21 20:18:27 +00:00
|
|
|
}
|