[HAL]
[reactos.git] / reactos / hal / halx86 / generic / halinit.c
index 29e997a..db54eb5 100644 (file)
-/* $Id$
- *
- * COPYRIGHT:     See COPYING in the top level directory
- * PROJECT:       ReactOS kernel
- * FILE:          ntoskrnl/hal/x86/halinit.c
- * PURPOSE:       Initalize the x86 hal
- * PROGRAMMER:    David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- *              11/06/98: Created
+/*
+ * PROJECT:         ReactOS HAL
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            hal/halx86/generic/halinit.c
+ * PURPOSE:         HAL Entrypoint and Initialization
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
 #include <hal.h>
-
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
 
-/* GLOBALS *****************************************************************/
+/* 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))
 
-PVOID HalpZeroPageMapping = NULL;
-HALP_HOOKS HalpHooks;
+BOOLEAN HalpPciLockSettings;
+ULONG HalpUsedAllocDescriptors;
+MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray[64];
+PVOID HalpHeapStart = MM_HAL_HEAP_START;
 
-/* FUNCTIONS ***************************************************************/
+/* PRIVATE FUNCTIONS *********************************************************/
 
-NTSTATUS
-STDCALL
-DriverEntry(
-    PDRIVER_OBJECT DriverObject,
-    PUNICODE_STRING RegistryPath)
+ULONG
+NTAPI
+HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+                        IN ULONG MaxAddress,
+                        IN ULONG PageCount,
+                        IN BOOLEAN Aligned)
 {
-       return STATUS_SUCCESS;
+    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;
 }
 
-BOOLEAN STDCALL
-HalInitSystem (ULONG BootPhase,
-               PLOADER_PARAMETER_BLOCK LoaderBlock)
+PVOID
+NTAPI
+HalpMapPhysicalMemory64(IN PHYSICAL_ADDRESS PhysicalAddress,
+                        IN ULONG PageCount)
 {
-  if (BootPhase == 0)
+    PHARDWARE_PTE PointerPte;
+    ULONG UsedPages = 0;
+    PVOID VirtualAddress, BaseAddress;
+
+    /* Start at the current HAL heap base */
+    BaseAddress = HalpHeapStart;
+    VirtualAddress = BaseAddress;
+
+    /* Loop until we have all the pages required */
+    while (UsedPages < PageCount)
     {
-      RtlZeroMemory(&HalpHooks, sizeof(HALP_HOOKS));
-      HalpInitPhase0();      
+        /* If this overflows past the HAL heap, it means there's no space */
+        if (VirtualAddress == NULL) return NULL;
+
+        /* Get the PTE for this address */
+        PointerPte = HalAddressToPte(VirtualAddress);
+
+        /* Go to the next page */
+        VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
+
+        /* Check if the page is available */
+        if (PointerPte->Valid)
+        {
+            /* PTE has data, skip it and start with a new base address */
+            BaseAddress = VirtualAddress;
+            UsedPages = 0;
+            continue;
+        }
+
+        /* PTE is available, keep going on this run */
+        UsedPages++;
     }
-  else if (BootPhase == 1)
+
+    /* 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)
     {
-      /* Initialize display and make the screen black */
-      HalInitializeDisplay (LoaderBlock);
-      HalpInitBusHandlers();
-      HalpInitDma();
-
-      /* Enumerate the devices on the motherboard */
-      HalpStartEnumerator();
-   }
-  else if (BootPhase == 2)
+        /* Past this allocation */
+        HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE));
+    }
+
+    /* Loop pages that can be mapped */
+    while (UsedPages--)
     {
-      /* Go to blue screen */
-      HalClearDisplay (0x17); /* grey on blue */
-      
-      HalpZeroPageMapping = MmMapIoSpace((LARGE_INTEGER)0LL, PAGE_SIZE, MmNonCached);
+        /* 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);
     }
 
-  return TRUE;
+    /* Flush the TLB and return the address */
+    HalpFlushTLB();
+    return VirtualAddress;
 }
 
-/* EOF */
+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;
+}
+
+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();
+    }
+}
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+HalInitSystem(IN ULONG BootPhase,
+              IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+    PKPRCB Prcb = KeGetCurrentPrcb();
+
+    /* Check the boot phase */
+    if (!BootPhase)
+    {
+        /* 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);
+        }
+
+#ifndef _MINIHAL_
+        /* Initialize ACPI */
+        HalpSetupAcpiPhase0(LoaderBlock);
+
+        /* Initialize the PICs */
+        HalpInitializePICs(TRUE);
+#endif
+
+        /* Force initial PIC state */
+        KfRaiseIrql(KeGetCurrentIrql());
+
+        /* Initialize CMOS lock */
+        KeInitializeSpinLock(&HalpSystemHardwareLock);
+
+        /* Initialize CMOS */
+        HalpInitializeCmos();
+
+        /* Fill out the dispatch tables */
+        HalQuerySystemInformation = HaliQuerySystemInformation;
+        HalSetSystemInformation = HaliSetSystemInformation;
+        HalInitPnpDriver = NULL; // FIXME: TODO
+#ifndef _MINIHAL_
+        HalGetDmaAdapter = HalpGetDmaAdapter;
+#else
+        HalGetDmaAdapter = NULL;
+#endif
+        HalGetInterruptTranslator = NULL;  // FIXME: TODO
+#ifndef _MINIHAL_
+        HalResetDisplay = HalpBiosDisplayReset;
+#else
+        HalResetDisplay = NULL;
+#endif
+        HalHaltSystem = HaliHaltSystem;
+
+        /* 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();
+
+#ifndef _MINIHAL_
+        /* Initialize the clock */
+        HalpInitializeClock();
+#endif
+
+        /*
+         * We could be rebooting with a pending profile interrupt,
+         * so clear it here before interrupts are enabled
+         */
+        HalStopProfileInterrupt(ProfileTime);
+
+        /* Do some HAL-specific initialization */
+        HalpInitPhase0(LoaderBlock);
+    }
+    else if (BootPhase == 1)
+    {
+        /* Initialize bus handlers */
+        HalpInitBusHandler();
+
+#ifndef _MINIHAL_
+        /* 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);
+
+        /* Initialize DMA. NT does this in Phase 0 */
+        HalpInitDma();
+#endif
+
+        /* Do some HAL-specific initialization */
+        HalpInitPhase1();
+    }
+
+    /* All done, return */
+    return TRUE;
+}