From 9e8cec3b58c8017d0a0d0dc0d607c73f15b41455 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Sat, 6 Jan 2007 22:31:50 +0000 Subject: [PATCH] Hal stubs. Build halppc. svn path=/branches/powerpc/; revision=25335 --- reactos/hal/halppc/directory.rbuild | 6 + reactos/hal/halppc/generic/beep.c | 42 + reactos/hal/halppc/generic/bus.c | 529 ++++++ reactos/hal/halppc/generic/display.c | 796 +++++++++ reactos/hal/halppc/generic/dma.c | 1950 +++++++++++++++++++++ reactos/hal/halppc/generic/drive.c | 33 + reactos/hal/halppc/generic/enum.c | 23 + reactos/hal/halppc/generic/fmutex.c | 101 ++ reactos/hal/halppc/generic/generic.rbuild | 26 + reactos/hal/halppc/generic/halinit.c | 69 + reactos/hal/halppc/generic/ipi.c | 24 + reactos/hal/halppc/generic/irq.S | 631 +++++++ reactos/hal/halppc/generic/irql.c | 425 +++++ reactos/hal/halppc/generic/isa.c | 75 + reactos/hal/halppc/generic/kdbg.c | 547 ++++++ reactos/hal/halppc/generic/mca.c | 79 + reactos/hal/halppc/generic/misc.c | 72 + reactos/hal/halppc/generic/pci.c | 812 +++++++++ reactos/hal/halppc/generic/portio.c | 289 +++ reactos/hal/halppc/generic/processor.c | 50 + reactos/hal/halppc/generic/pwroff.c | 121 ++ reactos/hal/halppc/generic/reboot.c | 41 + reactos/hal/halppc/generic/resource.c | 31 + reactos/hal/halppc/generic/spinlock.c | 191 ++ reactos/hal/halppc/generic/sysbus.c | 66 + reactos/hal/halppc/generic/sysinfo.c | 74 + reactos/hal/halppc/generic/systimer.S | 48 + reactos/hal/halppc/generic/time.c | 102 ++ reactos/hal/halppc/generic/timer.c | 205 +++ reactos/hal/halppc/include/apic.h | 214 +++ reactos/hal/halppc/include/bus.h | 133 ++ reactos/hal/halppc/include/hal.h | 37 + reactos/hal/halppc/include/haldma.h | 383 ++++ reactos/hal/halppc/include/halirq.h | 35 + reactos/hal/halppc/include/halp.h | 97 + reactos/hal/halppc/include/ioapic.h | 103 ++ reactos/hal/halppc/include/mps.h | 204 +++ reactos/hal/halppc/up/halinit_up.c | 35 + reactos/hal/halppc/up/halup.rbuild | 12 + reactos/hal/halppc/up/halup.rc | 5 + 40 files changed, 8716 insertions(+) create mode 100644 reactos/hal/halppc/directory.rbuild create mode 100644 reactos/hal/halppc/generic/beep.c create mode 100644 reactos/hal/halppc/generic/bus.c create mode 100644 reactos/hal/halppc/generic/display.c create mode 100644 reactos/hal/halppc/generic/dma.c create mode 100644 reactos/hal/halppc/generic/drive.c create mode 100644 reactos/hal/halppc/generic/enum.c create mode 100644 reactos/hal/halppc/generic/fmutex.c create mode 100644 reactos/hal/halppc/generic/generic.rbuild create mode 100644 reactos/hal/halppc/generic/halinit.c create mode 100644 reactos/hal/halppc/generic/ipi.c create mode 100644 reactos/hal/halppc/generic/irq.S create mode 100644 reactos/hal/halppc/generic/irql.c create mode 100644 reactos/hal/halppc/generic/isa.c create mode 100644 reactos/hal/halppc/generic/kdbg.c create mode 100644 reactos/hal/halppc/generic/mca.c create mode 100644 reactos/hal/halppc/generic/misc.c create mode 100644 reactos/hal/halppc/generic/pci.c create mode 100644 reactos/hal/halppc/generic/portio.c create mode 100644 reactos/hal/halppc/generic/processor.c create mode 100644 reactos/hal/halppc/generic/pwroff.c create mode 100644 reactos/hal/halppc/generic/reboot.c create mode 100644 reactos/hal/halppc/generic/resource.c create mode 100644 reactos/hal/halppc/generic/spinlock.c create mode 100644 reactos/hal/halppc/generic/sysbus.c create mode 100644 reactos/hal/halppc/generic/sysinfo.c create mode 100644 reactos/hal/halppc/generic/systimer.S create mode 100644 reactos/hal/halppc/generic/time.c create mode 100644 reactos/hal/halppc/generic/timer.c create mode 100644 reactos/hal/halppc/include/apic.h create mode 100644 reactos/hal/halppc/include/bus.h create mode 100644 reactos/hal/halppc/include/hal.h create mode 100644 reactos/hal/halppc/include/haldma.h create mode 100644 reactos/hal/halppc/include/halirq.h create mode 100644 reactos/hal/halppc/include/halp.h create mode 100644 reactos/hal/halppc/include/ioapic.h create mode 100644 reactos/hal/halppc/include/mps.h create mode 100644 reactos/hal/halppc/up/halinit_up.c create mode 100644 reactos/hal/halppc/up/halup.rbuild create mode 100644 reactos/hal/halppc/up/halup.rc diff --git a/reactos/hal/halppc/directory.rbuild b/reactos/hal/halppc/directory.rbuild new file mode 100644 index 00000000000..d1338a727ab --- /dev/null +++ b/reactos/hal/halppc/directory.rbuild @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/reactos/hal/halppc/generic/beep.c b/reactos/hal/halppc/generic/beep.c new file mode 100644 index 00000000000..f4e9d3b07ea --- /dev/null +++ b/reactos/hal/halppc/generic/beep.c @@ -0,0 +1,42 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/beep.c + * PURPOSE: Speaker function (it's only one) + * PROGRAMMER: Eric Kohl (ekohl@abo.rhein-zeitung.de) + * UPDATE HISTORY: + * Created 31/01/99 + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + +/* CONSTANTS *****************************************************************/ + +#define TIMER2 0x42 +#define TIMER3 0x43 +#define PORT_B 0x61 +#define CLOCKFREQ 1193167 + + +/* FUNCTIONS *****************************************************************/ +/* + * FUNCTION: Beeps the speaker. + * ARGUMENTS: + * Frequency = If 0, the speaker will be switched off, otherwise + * the speaker beeps with the specified frequency. + */ + +BOOLEAN +STDCALL +HalMakeBeep ( + ULONG Frequency + ) +{ + return TRUE; +} + diff --git a/reactos/hal/halppc/generic/bus.c b/reactos/hal/halppc/generic/bus.c new file mode 100644 index 00000000000..35bac840f2c --- /dev/null +++ b/reactos/hal/halppc/generic/bus.c @@ -0,0 +1,529 @@ +/* $Id: bus.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/bus.c + * PURPOSE: Bus functions + * PROGRAMMER: David Welch (welch@mcmail.com) + * UPDATE HISTORY: + * Created 22/05/98 + * + * + * TODO: + * - Add bus handler functions for all busses + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +#define TAG_BUS TAG('B', 'U', 'S', 'H') + +KSPIN_LOCK HalpBusHandlerSpinLock = {0,}; +LIST_ENTRY HalpBusHandlerList; + + +/* FUNCTIONS *****************************************************************/ + +static NTSTATUS STDCALL +HalpNoAdjustResourceList(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PCM_RESOURCE_LIST Resources) +{ + return STATUS_UNSUCCESSFUL; +} + + +static NTSTATUS STDCALL +HalpNoAssignSlotResources(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PUNICODE_STRING RegistryPath, + PUNICODE_STRING DriverClassName, + PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject, + ULONG SlotNumber, + PCM_RESOURCE_LIST *AllocatedResources) +{ + return STATUS_NOT_SUPPORTED; +} + + +static ULONG STDCALL +HalpNoBusData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + return 0; +} + + +static ULONG STDCALL +HalpNoGetInterruptVector(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG BusInterruptLevel, + ULONG BusInterruptVector, + PKIRQL Irql, + PKAFFINITY Affinity) +{ + return 0; +} + + +static ULONG STDCALL +HalpNoTranslateBusAddress(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PHYSICAL_ADDRESS BusAddress, + PULONG AddressSpace, + PPHYSICAL_ADDRESS TranslatedAddress) +{ + return 0; +} + + +PBUS_HANDLER +HalpAllocateBusHandler(INTERFACE_TYPE InterfaceType, + BUS_DATA_TYPE BusDataType, + ULONG BusNumber) +{ + PBUS_HANDLER BusHandler = NULL; + + DPRINT("HalpAllocateBusHandler()\n"); + + BusHandler = ExAllocatePoolWithTag(NonPagedPool, + sizeof(BUS_HANDLER), + TAG_BUS); + if (BusHandler == NULL) + return NULL; + + RtlZeroMemory(BusHandler, + sizeof(BUS_HANDLER)); + + InsertTailList(&HalpBusHandlerList, + &BusHandler->Entry); + + BusHandler->InterfaceType = InterfaceType; + BusHandler->BusDataType = BusDataType; + BusHandler->BusNumber = BusNumber; + + /* initialize default bus handler functions */ + BusHandler->GetBusData = HalpNoBusData; + BusHandler->SetBusData = HalpNoBusData; + BusHandler->AdjustResourceList = HalpNoAdjustResourceList; + BusHandler->AssignSlotResources = HalpNoAssignSlotResources; + BusHandler->GetInterruptVector = HalpNoGetInterruptVector; + BusHandler->TranslateBusAddress = HalpNoTranslateBusAddress; + + /* any more ?? */ + + DPRINT("HalpAllocateBusHandler() done\n"); + + return BusHandler; +} + + +VOID +HalpInitBusHandlers(VOID) +{ + PBUS_HANDLER BusHandler; + + /* General preparations */ + KeInitializeSpinLock(&HalpBusHandlerSpinLock); + InitializeListHead(&HalpBusHandlerList); + + /* Initialize hal dispatch tables */ + HalQuerySystemInformation = HalpQuerySystemInformation; + +#if 0 + HalSetSystemInformation = HalpSetSystemInformation; + + HalQueryBusSlots = HalpQueryBusSlots; +#endif + + /* Add system bus handler */ + BusHandler = HalpAllocateBusHandler(Internal, + ConfigurationSpaceUndefined, + 0); + if (BusHandler == NULL) + return; + BusHandler->GetInterruptVector = + (pGetInterruptVector)HalpGetSystemInterruptVector; + BusHandler->TranslateBusAddress = + (pTranslateBusAddress)HalpTranslateSystemBusAddress; + + /* Add cmos bus handler */ + BusHandler = HalpAllocateBusHandler(InterfaceTypeUndefined, + Cmos, + 0); + if (BusHandler == NULL) + return; + BusHandler->GetBusData = (pGetSetBusData)HalpGetCmosData; + BusHandler->SetBusData = (pGetSetBusData)HalpSetCmosData; + + /* Add isa bus handler */ + BusHandler = HalpAllocateBusHandler(Isa, + ConfigurationSpaceUndefined, + 0); + if (BusHandler == NULL) + return; + + BusHandler->GetInterruptVector = + (pGetInterruptVector)HalpGetIsaInterruptVector; + BusHandler->TranslateBusAddress = + (pTranslateBusAddress)HalpTranslateIsaBusAddress; + + /* Add MicroChannel bus handler */ + BusHandler = HalpAllocateBusHandler(MicroChannel, + Pos, + 0); + if (BusHandler == NULL) + return; + + BusHandler->GetBusData = (pGetSetBusData)HalpGetMicroChannelData; +} + + +PBUS_HANDLER FASTCALL +HaliHandlerForBus(INTERFACE_TYPE InterfaceType, + ULONG BusNumber) +{ + PBUS_HANDLER BusHandler; + PLIST_ENTRY CurrentEntry; + KIRQL OldIrql; + + KeAcquireSpinLock(&HalpBusHandlerSpinLock, + &OldIrql); + + CurrentEntry = HalpBusHandlerList.Flink; + while (CurrentEntry != &HalpBusHandlerList) + { + BusHandler = (PBUS_HANDLER)CurrentEntry; + if (BusHandler->InterfaceType == InterfaceType && + BusHandler->BusNumber == BusNumber) + { + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + return BusHandler; + } + CurrentEntry = CurrentEntry->Flink; + } + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + + return NULL; +} + + +PBUS_HANDLER FASTCALL +HaliHandlerForConfigSpace(BUS_DATA_TYPE BusDataType, + ULONG BusNumber) +{ + PBUS_HANDLER BusHandler; + PLIST_ENTRY CurrentEntry; + KIRQL OldIrql; + + KeAcquireSpinLock(&HalpBusHandlerSpinLock, + &OldIrql); + + CurrentEntry = HalpBusHandlerList.Flink; + while (CurrentEntry != &HalpBusHandlerList) + { + BusHandler = (PBUS_HANDLER)CurrentEntry; + if (BusHandler->BusDataType == BusDataType && + BusHandler->BusNumber == BusNumber) + { + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + return BusHandler; + } + CurrentEntry = CurrentEntry->Flink; + } + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + + return NULL; +} + + +PBUS_HANDLER FASTCALL +HaliReferenceHandlerForBus(INTERFACE_TYPE InterfaceType, + ULONG BusNumber) +{ + PBUS_HANDLER BusHandler; + PLIST_ENTRY CurrentEntry; + KIRQL OldIrql; + + KeAcquireSpinLock(&HalpBusHandlerSpinLock, + &OldIrql); + + CurrentEntry = HalpBusHandlerList.Flink; + while (CurrentEntry != &HalpBusHandlerList) + { + BusHandler = (PBUS_HANDLER)CurrentEntry; + if (BusHandler->InterfaceType == InterfaceType && + BusHandler->BusNumber == BusNumber) + { + BusHandler->RefCount++; + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + return BusHandler; + } + CurrentEntry = CurrentEntry->Flink; + } + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + + return NULL; +} + + +PBUS_HANDLER FASTCALL +HaliReferenceHandlerForConfigSpace(BUS_DATA_TYPE BusDataType, + ULONG BusNumber) +{ + PBUS_HANDLER BusHandler; + PLIST_ENTRY CurrentEntry; + KIRQL OldIrql; + + KeAcquireSpinLock(&HalpBusHandlerSpinLock, + &OldIrql); + + CurrentEntry = HalpBusHandlerList.Flink; + while (CurrentEntry != &HalpBusHandlerList) + { + BusHandler = (PBUS_HANDLER)CurrentEntry; + if (BusHandler->BusDataType == BusDataType && + BusHandler->BusNumber == BusNumber) + { + BusHandler->RefCount++; + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + return BusHandler; + } + CurrentEntry = CurrentEntry->Flink; + } + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); + + return NULL; +} + + +VOID FASTCALL +HaliDereferenceBusHandler(PBUS_HANDLER BusHandler) +{ + KIRQL OldIrql; + + KeAcquireSpinLock(&HalpBusHandlerSpinLock, + &OldIrql); + BusHandler->RefCount--; + KeReleaseSpinLock(&HalpBusHandlerSpinLock, + OldIrql); +} + + +NTSTATUS STDCALL +HalAdjustResourceList(PCM_RESOURCE_LIST Resources) +{ + PBUS_HANDLER BusHandler; + NTSTATUS Status; + + BusHandler = HaliReferenceHandlerForBus(Resources->List[0].InterfaceType, + Resources->List[0].BusNumber); + if (BusHandler == NULL) + return STATUS_SUCCESS; + + Status = BusHandler->AdjustResourceList(BusHandler, + Resources->List[0].BusNumber, + Resources); + HaliDereferenceBusHandler (BusHandler); + + return Status; +} + + +NTSTATUS STDCALL +HalAssignSlotResources(PUNICODE_STRING RegistryPath, + PUNICODE_STRING DriverClassName, + PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject, + INTERFACE_TYPE BusType, + ULONG BusNumber, + ULONG SlotNumber, + PCM_RESOURCE_LIST *AllocatedResources) +{ + PBUS_HANDLER BusHandler; + NTSTATUS Status; + + BusHandler = HaliReferenceHandlerForBus(BusType, + BusNumber); + if (BusHandler == NULL) + return STATUS_NOT_FOUND; + + Status = BusHandler->AssignSlotResources(BusHandler, + BusNumber, + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + SlotNumber, + AllocatedResources); + + HaliDereferenceBusHandler(BusHandler); + + return Status; +} + + +ULONG STDCALL +HalGetBusData(BUS_DATA_TYPE BusDataType, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Length) +{ + return (HalGetBusDataByOffset(BusDataType, + BusNumber, + SlotNumber, + Buffer, + 0, + Length)); +} + + +ULONG STDCALL +HalGetBusDataByOffset(BUS_DATA_TYPE BusDataType, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + PBUS_HANDLER BusHandler; + ULONG Result; + + BusHandler = HaliReferenceHandlerForConfigSpace(BusDataType, + BusNumber); + if (BusHandler == NULL) + return 0; + + Result = BusHandler->GetBusData(BusHandler, + BusNumber, + SlotNumber, + Buffer, + Offset, + Length); + + HaliDereferenceBusHandler (BusHandler); + + return Result; +} + + +ULONG STDCALL +HalGetInterruptVector(INTERFACE_TYPE InterfaceType, + ULONG BusNumber, + ULONG BusInterruptLevel, + ULONG BusInterruptVector, + PKIRQL Irql, + PKAFFINITY Affinity) +{ + PBUS_HANDLER BusHandler; + ULONG Result; + + BusHandler = HaliReferenceHandlerForBus(InterfaceType, + BusNumber); + if (BusHandler == NULL) + return 0; + + Result = BusHandler->GetInterruptVector(BusHandler, + BusNumber, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity); + + HaliDereferenceBusHandler(BusHandler); + + return Result; +} + + +ULONG STDCALL +HalSetBusData(BUS_DATA_TYPE BusDataType, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Length) +{ + return (HalSetBusDataByOffset(BusDataType, + BusNumber, + SlotNumber, + Buffer, + 0, + Length)); +} + + +ULONG STDCALL +HalSetBusDataByOffset(BUS_DATA_TYPE BusDataType, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + PBUS_HANDLER BusHandler; + ULONG Result; + + BusHandler = HaliReferenceHandlerForConfigSpace(BusDataType, + BusNumber); + if (BusHandler == NULL) + return 0; + + Result = BusHandler->SetBusData(BusHandler, + BusNumber, + SlotNumber, + Buffer, + Offset, + Length); + + HaliDereferenceBusHandler(BusHandler); + + return Result; +} + + +BOOLEAN STDCALL +HalTranslateBusAddress(INTERFACE_TYPE InterfaceType, + ULONG BusNumber, + PHYSICAL_ADDRESS BusAddress, + PULONG AddressSpace, + PPHYSICAL_ADDRESS TranslatedAddress) +{ + PBUS_HANDLER BusHandler; + BOOLEAN Result; + + BusHandler = HaliReferenceHandlerForBus(InterfaceType, + BusNumber); + if (BusHandler == NULL) + return FALSE; + + Result = (BOOLEAN)BusHandler->TranslateBusAddress(BusHandler, + BusNumber, + BusAddress, + AddressSpace, + TranslatedAddress); + + HaliDereferenceBusHandler(BusHandler); + + return Result; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/display.c b/reactos/hal/halppc/generic/display.c new file mode 100644 index 00000000000..1874de23331 --- /dev/null +++ b/reactos/hal/halppc/generic/display.c @@ -0,0 +1,796 @@ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001, 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: display.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/display.c + * PURPOSE: Blue screen display + * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + * UPDATE HISTORY: + * Created 08/10/99 + */ + +/* + * Portions of this code are from the XFree86 Project and available from the + * following license: + * + * Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- + * NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the XFree86 Project shall + * not be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from the + * XFree86 Project. +*/ + +/* DISPLAY OWNERSHIP + * + * So, who owns the physical display and is allowed to write to it? + * + * In MS NT, upon boot HAL owns the display. Somewhere in the boot + * sequence (haven't figured out exactly where or by who), some + * component calls HalAcquireDisplayOwnership. From that moment on, + * the display is owned by that component and is switched to graphics + * mode. The display is not supposed to return to text mode, except + * in case of a bug check. The bug check will call HalDisplayString + * to output a string to the text screen. HAL will notice that it + * currently doesn't own the display and will re-take ownership, by + * calling the callback function passed to HalAcquireDisplayOwnership. + * After the bugcheck, execution is halted. So, under NT, the only + * possible sequence of display modes is text mode -> graphics mode -> + * text mode (the latter hopefully happening very infrequently). + * + * Things are a little bit different in the current state of ReactOS. + * We want to have a functional interactive text mode. We should be + * able to switch from text mode to graphics mode when a GUI app is + * started and switch back to text mode when it's finished. Then, when + * another GUI app is started, another switch to and from graphics mode + * is possible. Also, when the system bugchecks in graphics mode we want + * to switch back to text mode to show the registers and stack trace. + * Last but not least, HalDisplayString is used a lot more in ReactOS, + * e.g. to print debug messages when the /DEBUGPORT=SCREEN boot option + * is present. + * 3 Components are involved in Reactos: HAL, BLUE.SYS and VIDEOPRT.SYS. + * As in NT, on boot HAL owns the display. When entering the text mode + * command interpreter, BLUE.SYS kicks in. It will write directly to the + * screen, more or less behind HALs back. + * When a GUI app is started, WIN32K.SYS will open the DISPLAY device. + * This open call will end up in VIDEOPRT.SYS. That component will then + * take ownership of the display by calling HalAcquireDisplayOwnership. + * When the GUI app terminates (WIN32K.SYS will close the DISPLAY device), + * we want to give ownership of the display back to HAL. Using the + * standard exported HAL functions, that's a bit of a problem, because + * there is no function defined to do that. In NT, this is handled by + * HalDisplayString, but that solution isn't satisfactory in ReactOS, + * because HalDisplayString is (in some cases) also used to output debug + * messages. If we do it the NT way, the first debug message output while + * in graphics mode would switch the display back to text mode. + * So, instead, if HalDisplayString detects that HAL doesn't have ownership + * of the display, it doesn't do anything. + * To return ownership to HAL, a new function is exported, + * HalReleaseDisplayOwnership. This function is called by the DISPLAY + * device Close routine in VIDEOPRT.SYS. It is also called at the beginning + * of a bug check, so HalDisplayString is activated again. + * Now, while the display is in graphics mode (not owned by HAL), BLUE.SYS + * should also refrain from writing to the screen buffer. The text mode + * screen buffer might overlap the graphics mode screen buffer, so changing + * something in the text mode buffer might mess up the graphics screen. To + * allow BLUE.SYS to detect if HAL owns the display, another new function is + * exported, HalQueryDisplayOwnership. BLUE.SYS will call this function to + * check if it's allowed to touch the text mode buffer. + * + * In an ideal world, when HAL takes ownership of the display, it should set + * up the CRT using real-mode (actually V86 mode, but who cares) INT 0x10 + * calls. Unfortunately, this will require HAL to setup a real-mode interrupt + * table etc. So, we chickened out of that by having the loader set up the + * display before switching to protected mode. If HAL is given back ownership + * after a GUI app terminates, the INT 0x10 calls are made by VIDEOPRT.SYS, + * since there is already support for them via the VideoPortInt10 routine. + */ + +#include +#define NDEBUG +#include + + +#define SCREEN_SYNCHRONIZATION + +#define VGA_GRAPH_MEM 0xa0000 +#define VGA_CHAR_MEM 0xb8000 +#define VGA_END_MEM 0xbffff + +#define VGA_AC_INDEX 0x3c0 +#define VGA_AC_READ 0x3c1 +#define VGA_AC_WRITE 0x3c0 + +#define VGA_MISC_WRITE 0x3c2 + +#define VGA_SEQ_INDEX 0x3c4 +#define VGA_SEQ_DATA 0x3c5 + +#define VGA_DAC_MASK 0x3c6 +#define VGA_DAC_READ_INDEX 0x3c7 +#define VGA_DAC_WRITE_INDEX 0x3c8 +#define VGA_DAC_DATA 0x3c9 +#define VGA_FEATURE_READ 0x3ca +#define VGA_MISC_READ 0x3cc + +#define VGA_GC_INDEX 0x3ce +#define VGA_GC_DATA 0x3cf + +#define VGA_CRTC_INDEX 0x3d4 +#define VGA_CRTC_DATA 0x3d5 + +#define VGA_INSTAT_READ 0x3da + +#define VGA_SEQ_NUM_REGISTERS 5 +#define VGA_CRTC_NUM_REGISTERS 25 +#define VGA_GC_NUM_REGISTERS 9 +#define VGA_AC_NUM_REGISTERS 21 + +#define CRTC_COLUMNS 0x01 +#define CRTC_OVERFLOW 0x07 +#define CRTC_ROWS 0x12 +#define CRTC_SCANLINES 0x09 + +#define CRTC_CURHI 0x0e +#define CRTC_CURLO 0x0f + + +#define CHAR_ATTRIBUTE_BLACK 0x00 /* black on black */ +#define CHAR_ATTRIBUTE 0x17 /* grey on blue */ + +#define FONT_AMOUNT (8*8192) + +/* VARIABLES ****************************************************************/ + +static ULONG CursorX = 0; /* Cursor Position */ +static ULONG CursorY = 0; +static ULONG SizeX = 80; /* Display size */ +static ULONG SizeY = 25; + +static BOOLEAN DisplayInitialized = FALSE; +static BOOLEAN HalOwnsDisplay = TRUE; + +static PUSHORT VideoBuffer = NULL; +static PUCHAR GraphVideoBuffer = NULL; + +static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters = NULL; + +static UCHAR SavedTextPalette[768]; +static UCHAR SavedTextMiscOutReg; +static UCHAR SavedTextCrtcReg[VGA_CRTC_NUM_REGISTERS]; +static UCHAR SavedTextAcReg[VGA_AC_NUM_REGISTERS]; +static UCHAR SavedTextGcReg[VGA_GC_NUM_REGISTERS]; +static UCHAR SavedTextSeqReg[VGA_SEQ_NUM_REGISTERS]; +static UCHAR SavedTextFont[2][FONT_AMOUNT]; +static BOOLEAN TextPaletteEnabled = FALSE; + +/* PRIVATE FUNCTIONS *********************************************************/ + +VOID FASTCALL +HalClearDisplay (UCHAR CharAttribute) +{ + WORD *ptr = (WORD*)VideoBuffer; + ULONG i; + + for (i = 0; i < SizeX * SizeY; i++, ptr++) + *ptr = ((CharAttribute << 8) + ' '); + + CursorX = 0; + CursorY = 0; +} + + +/* STATIC FUNCTIONS *********************************************************/ + +VOID STATIC +HalScrollDisplay (VOID) +{ + PUSHORT ptr; + int i; + + ptr = VideoBuffer + SizeX; + RtlMoveMemory(VideoBuffer, + ptr, + SizeX * (SizeY - 1) * 2); + + ptr = VideoBuffer + (SizeX * (SizeY - 1)); + for (i = 0; i < (int)SizeX; i++, ptr++) + { + *ptr = (CHAR_ATTRIBUTE << 8) + ' '; + } +} + +VOID STATIC FASTCALL +HalPutCharacter (CHAR Character) +{ + PUSHORT ptr; + + ptr = VideoBuffer + ((CursorY * SizeX) + CursorX); + *ptr = (CHAR_ATTRIBUTE << 8) + Character; +} + +VOID STATIC +HalDisablePalette(VOID) +{ + (VOID)READ_PORT_UCHAR((PUCHAR)VGA_INSTAT_READ); + WRITE_PORT_UCHAR((PUCHAR)VGA_AC_INDEX, 0x20); + TextPaletteEnabled = FALSE; +} + +VOID STATIC +HalEnablePalette(VOID) +{ + (VOID)READ_PORT_UCHAR((PUCHAR)VGA_INSTAT_READ); + WRITE_PORT_UCHAR((PUCHAR)VGA_AC_INDEX, 0x00); + TextPaletteEnabled = TRUE; +} + +UCHAR STATIC FASTCALL +HalReadGc(ULONG Index) +{ + WRITE_PORT_UCHAR((PUCHAR)VGA_GC_INDEX, (UCHAR)Index); + return(READ_PORT_UCHAR((PUCHAR)VGA_GC_DATA)); +} + +VOID STATIC FASTCALL +HalWriteGc(ULONG Index, UCHAR Value) +{ + WRITE_PORT_UCHAR((PUCHAR)VGA_GC_INDEX, (UCHAR)Index); + WRITE_PORT_UCHAR((PUCHAR)VGA_GC_DATA, Value); +} + +UCHAR STATIC FASTCALL +HalReadSeq(ULONG Index) +{ + WRITE_PORT_UCHAR((PUCHAR)VGA_SEQ_INDEX, (UCHAR)Index); + return(READ_PORT_UCHAR((PUCHAR)VGA_SEQ_DATA)); +} + +VOID STATIC FASTCALL +HalWriteSeq(ULONG Index, UCHAR Value) +{ + WRITE_PORT_UCHAR((PUCHAR)VGA_SEQ_INDEX, (UCHAR)Index); + WRITE_PORT_UCHAR((PUCHAR)VGA_SEQ_DATA, Value); +} + +VOID STATIC FASTCALL +HalWriteAc(ULONG Index, UCHAR Value) +{ + if (TextPaletteEnabled) + { + Index &= ~0x20; + } + else + { + Index |= 0x20; + } + (VOID)READ_PORT_UCHAR((PUCHAR)VGA_INSTAT_READ); + WRITE_PORT_UCHAR((PUCHAR)VGA_AC_INDEX, (UCHAR)Index); + WRITE_PORT_UCHAR((PUCHAR)VGA_AC_WRITE, Value); +} + +UCHAR STATIC FASTCALL +HalReadAc(ULONG Index) +{ + if (TextPaletteEnabled) + { + Index &= ~0x20; + } + else + { + Index |= 0x20; + } + (VOID)READ_PORT_UCHAR((PUCHAR)VGA_INSTAT_READ); + WRITE_PORT_UCHAR((PUCHAR)VGA_AC_INDEX, (UCHAR)Index); + return(READ_PORT_UCHAR((PUCHAR)VGA_AC_READ)); +} + +VOID STATIC FASTCALL +HalWriteCrtc(ULONG Index, UCHAR Value) +{ + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, (UCHAR)Index); + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA, Value); +} + +UCHAR STATIC FASTCALL +HalReadCrtc(ULONG Index) +{ + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, (UCHAR)Index); + return(READ_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA)); +} + +VOID STATIC FASTCALL +HalResetSeq(BOOLEAN Start) +{ + if (Start) + { + HalWriteSeq(0x00, 0x01); + } + else + { + HalWriteSeq(0x00, 0x03); + } +} + +VOID STATIC FASTCALL +HalBlankScreen(BOOLEAN On) +{ + UCHAR Scrn; + + Scrn = HalReadSeq(0x01); + + if (On) + { + Scrn &= ~0x20; + } + else + { + Scrn |= 0x20; + } + + HalResetSeq(TRUE); + HalWriteSeq(0x01, Scrn); + HalResetSeq(FALSE); +} + +VOID STATIC +HalSaveFont(VOID) +{ + UCHAR Attr10; + UCHAR MiscOut, Gc4, Gc5, Gc6, Seq2, Seq4; + ULONG i; + + /* Check if we are already in graphics mode. */ + Attr10 = HalReadAc(0x10); + if (Attr10 & 0x01) + { + return; + } + + /* Save registers. */ + MiscOut = READ_PORT_UCHAR((PUCHAR)VGA_MISC_READ); + Gc4 = HalReadGc(0x04); + Gc5 = HalReadGc(0x05); + Gc6 = HalReadGc(0x06); + Seq2 = HalReadSeq(0x02); + Seq4 = HalReadSeq(0x04); + + /* Force colour mode. */ + WRITE_PORT_UCHAR((PUCHAR)VGA_MISC_WRITE, (UCHAR)(MiscOut | 0x01)); + + HalBlankScreen(FALSE); + + for (i = 0; i < 2; i++) + { + /* Save font 1 */ + HalWriteSeq(0x02, (UCHAR)(0x04 << i)); /* Write to plane 2 or 3 */ + HalWriteSeq(0x04, 0x06); /* Enable plane graphics. */ + HalWriteGc(0x04, (UCHAR)(0x02 + i)); /* Read plane 2 or 3 */ + HalWriteGc(0x05, 0x00); /* Write mode 0; read mode 0 */ + HalWriteGc(0x06, 0x05); /* Set graphics. */ + memcpy(SavedTextFont[i], GraphVideoBuffer, FONT_AMOUNT); + } + + /* Restore registers. */ + HalWriteAc(0x10, Attr10); + HalWriteSeq(0x02, Seq2); + HalWriteSeq(0x04, Seq4); + HalWriteGc(0x04, Gc4); + HalWriteGc(0x05, Gc5); + HalWriteGc(0x06, Gc6); + WRITE_PORT_UCHAR((PUCHAR)VGA_MISC_WRITE, MiscOut); + + HalBlankScreen(TRUE); +} + +VOID STATIC +HalSaveMode(VOID) +{ + ULONG i; + + SavedTextMiscOutReg = READ_PORT_UCHAR((PUCHAR)VGA_MISC_READ); + + for (i = 0; i < VGA_CRTC_NUM_REGISTERS; i++) + { + SavedTextCrtcReg[i] = HalReadCrtc(i); + } + + HalEnablePalette(); + for (i = 0; i < VGA_AC_NUM_REGISTERS; i++) + { + SavedTextAcReg[i] = HalReadAc(i); + } + HalDisablePalette(); + + for (i = 0; i < VGA_GC_NUM_REGISTERS; i++) + { + SavedTextGcReg[i] = HalReadGc(i); + } + + for (i = 0; i < VGA_SEQ_NUM_REGISTERS; i++) + { + SavedTextSeqReg[i] = HalReadSeq(i); + } +} + +VOID STATIC +HalDacDelay(VOID) +{ + (VOID)READ_PORT_UCHAR((PUCHAR)VGA_INSTAT_READ); + (VOID)READ_PORT_UCHAR((PUCHAR)VGA_INSTAT_READ); +} + +VOID STATIC +HalSavePalette(VOID) +{ + ULONG i; + WRITE_PORT_UCHAR((PUCHAR)VGA_DAC_MASK, 0xFF); + WRITE_PORT_UCHAR((PUCHAR)VGA_DAC_READ_INDEX, 0x00); + for (i = 0; i < 768; i++) + { + SavedTextPalette[i] = READ_PORT_UCHAR((PUCHAR)VGA_DAC_DATA); + HalDacDelay(); + } +} + +VOID STATIC +HalRestoreFont(VOID) +{ + UCHAR MiscOut, Attr10, Gc1, Gc3, Gc4, Gc5, Gc6, Gc8; + UCHAR Seq2, Seq4; + ULONG i; + + /* Save registers. */ + MiscOut = READ_PORT_UCHAR((PUCHAR)VGA_MISC_READ); + Attr10 = HalReadAc(0x10); + Gc1 = HalReadGc(0x01); + Gc3 = HalReadGc(0x03); + Gc4 = HalReadGc(0x04); + Gc5 = HalReadGc(0x05); + Gc6 = HalReadGc(0x06); + Gc8 = HalReadGc(0x08); + Seq2 = HalReadSeq(0x02); + Seq4 = HalReadSeq(0x04); + + /* Force into colour mode. */ + WRITE_PORT_UCHAR((PUCHAR)VGA_MISC_WRITE, (UCHAR)(MiscOut | 0x10)); + + HalBlankScreen(FALSE); + + HalWriteGc(0x03, 0x00); /* Don't rotate; write unmodified. */ + HalWriteGc(0x08, 0xFF); /* Write all bits. */ + HalWriteGc(0x01, 0x00); /* All planes from CPU. */ + + for (i = 0; i < 2; i++) + { + HalWriteSeq(0x02, (UCHAR)(0x04 << i)); /* Write to plane 2 or 3 */ + HalWriteSeq(0x04, 0x06); /* Enable plane graphics. */ + HalWriteGc(0x04, (UCHAR)(0x02 + i)); /* Read plane 2 or 3 */ + HalWriteGc(0x05, 0x00); /* Write mode 0; read mode 0. */ + HalWriteGc(0x06, 0x05); /* Set graphics. */ + memcpy(GraphVideoBuffer, SavedTextFont[i], FONT_AMOUNT); + } + + HalBlankScreen(TRUE); + + /* Restore registers. */ + WRITE_PORT_UCHAR((PUCHAR)VGA_MISC_WRITE, MiscOut); + HalWriteAc(0x10, Attr10); + HalWriteGc(0x01, Gc1); + HalWriteGc(0x03, Gc3); + HalWriteGc(0x04, Gc4); + HalWriteGc(0x05, Gc5); + HalWriteGc(0x06, Gc6); + HalWriteGc(0x08, Gc8); + HalWriteSeq(0x02, Seq2); + HalWriteSeq(0x04, Seq4); +} + +VOID STATIC +HalRestoreMode(VOID) +{ + ULONG i; + + WRITE_PORT_UCHAR((PUCHAR)VGA_MISC_WRITE, SavedTextMiscOutReg); + + for (i = 1; i < VGA_SEQ_NUM_REGISTERS; i++) + { + HalWriteSeq(i, SavedTextSeqReg[i]); + } + + /* Unlock CRTC registers 0-7 */ + HalWriteCrtc(17, (UCHAR)(SavedTextCrtcReg[17] & ~0x80)); + + for (i = 0; i < VGA_CRTC_NUM_REGISTERS; i++) + { + HalWriteCrtc(i, SavedTextCrtcReg[i]); + } + + for (i = 0; i < VGA_GC_NUM_REGISTERS; i++) + { + HalWriteGc(i, SavedTextGcReg[i]); + } + + HalEnablePalette(); + for (i = 0; i < VGA_AC_NUM_REGISTERS; i++) + { + HalWriteAc(i, SavedTextAcReg[i]); + } + HalDisablePalette(); +} + +VOID STATIC +HalRestorePalette(VOID) +{ + ULONG i; + WRITE_PORT_UCHAR((PUCHAR)VGA_DAC_MASK, 0xFF); + WRITE_PORT_UCHAR((PUCHAR)VGA_DAC_WRITE_INDEX, 0x00); + for (i = 0; i < 768; i++) + { + WRITE_PORT_UCHAR((PUCHAR)VGA_DAC_DATA, SavedTextPalette[i]); + HalDacDelay(); + } + HalDisablePalette(); +} + +/* PRIVATE FUNCTIONS ********************************************************/ + +VOID FASTCALL +HalInitializeDisplay (PROS_LOADER_PARAMETER_BLOCK LoaderBlock) +/* + * FUNCTION: Initalize the display + * ARGUMENTS: + * InitParameters = Parameters setup by the boot loader + */ +{ + PHYSICAL_ADDRESS PhysBuffer; + + if (! DisplayInitialized) + { + ULONG ScanLines; + ULONG Data; + + PhysBuffer.u.HighPart = 0; + PhysBuffer.u.LowPart = VGA_GRAPH_MEM; + GraphVideoBuffer = MmMapIoSpace(PhysBuffer, VGA_END_MEM - VGA_GRAPH_MEM + 1, MmNonCached); + if (NULL == GraphVideoBuffer) + { + return; + } + VideoBuffer = (PUSHORT) (GraphVideoBuffer + (VGA_CHAR_MEM - VGA_GRAPH_MEM)); + + /* Set cursor position */ +// CursorX = LoaderBlock->cursorx; +// CursorY = LoaderBlock->cursory; + CursorX = 0; + CursorY = 0; + + /* read screen size from the crtc */ + /* FIXME: screen size should be read from the boot parameters */ + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_COLUMNS); + SizeX = READ_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA) + 1; + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_ROWS); + SizeY = READ_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA); + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_OVERFLOW); + Data = READ_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA); + SizeY |= (((Data & 0x02) << 7) | ((Data & 0x40) << 3)); + SizeY++; + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_SCANLINES); + ScanLines = (READ_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA) & 0x1F) + 1; + SizeY = SizeY / ScanLines; + +#ifdef BOCHS_30ROWS + SizeY=30; +#endif + HalClearDisplay(CHAR_ATTRIBUTE_BLACK); + + DisplayInitialized = TRUE; + + /* + Save the VGA state at this point so we can restore it on a bugcheck. + */ + HalSavePalette(); + HalSaveMode(); + HalSaveFont(); + } +} + + +/* PUBLIC FUNCTIONS *********************************************************/ + +VOID STDCALL +HalReleaseDisplayOwnership(VOID) +/* + * FUNCTION: Release ownership of display back to HAL + */ +{ + if (HalResetDisplayParameters == NULL) + return; + + if (HalOwnsDisplay == TRUE) + return; + + if (!HalResetDisplayParameters(SizeX, SizeY)) + { + HalRestoreMode(); + HalRestoreFont(); + HalRestorePalette(); + } + HalOwnsDisplay = TRUE; + HalClearDisplay(CHAR_ATTRIBUTE); +} + + +VOID STDCALL +HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters) +/* + * FUNCTION: + * ARGUMENTS: + * ResetDisplayParameters = Pointer to a driver specific + * reset routine. + */ +{ + HalOwnsDisplay = FALSE; + HalResetDisplayParameters = ResetDisplayParameters; +} + +VOID STDCALL +HalDisplayString(IN PCH String) +/* + * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there + * already and displays a string + * ARGUMENT: + * string = ASCII string to display + * NOTE: Use with care because there is no support for returning from BSOD + * mode + */ +{ + PCH pch; +#ifdef SCREEN_SYNCHRONIZATION + int offset; +#endif + static KSPIN_LOCK Lock; + KIRQL OldIrql; + ULONG Flags; + + /* See comment at top of file */ + if (! HalOwnsDisplay || ! DisplayInitialized) + { + return; + } + + pch = String; + + OldIrql = KfRaiseIrql(HIGH_LEVEL); + KiAcquireSpinLock(&Lock); + + Ki386SaveFlags(Flags); + Ki386DisableInterrupts(); + +#ifdef SCREEN_SYNCHRONIZATION + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_CURHI); + offset = READ_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA)<<8; + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_CURLO); + offset += READ_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA); + + CursorY = offset / SizeX; + CursorX = offset % SizeX; +#endif + + while (*pch != 0) + { + if (*pch == '\n') + { + CursorY++; + CursorX = 0; + } + else if (*pch == '\b') + { + if (CursorX > 0) + { + CursorX--; + } + } + else if (*pch != '\r') + { + HalPutCharacter (*pch); + CursorX++; + + if (CursorX >= SizeX) + { + CursorY++; + CursorX = 0; + } + } + + if (CursorY >= SizeY) + { + HalScrollDisplay (); + CursorY = SizeY - 1; + } + + pch++; + } + +#ifdef SCREEN_SYNCHRONIZATION + offset = (CursorY * SizeX) + CursorX; + + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_CURLO); + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA, (UCHAR)(offset & 0xff)); + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, CRTC_CURHI); + WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA, (UCHAR)((offset >> 8) & 0xff)); +#endif + Ki386RestoreFlags(Flags); + + KiReleaseSpinLock(&Lock); + KfLowerIrql(OldIrql); +} + +VOID STDCALL +HalQueryDisplayParameters(OUT PULONG DispSizeX, + OUT PULONG DispSizeY, + OUT PULONG CursorPosX, + OUT PULONG CursorPosY) +{ + if (DispSizeX) + *DispSizeX = SizeX; + if (DispSizeY) + *DispSizeY = SizeY; + if (CursorPosX) + *CursorPosX = CursorX; + if (CursorPosY) + *CursorPosY = CursorY; +} + + +VOID STDCALL +HalSetDisplayParameters(IN ULONG CursorPosX, + IN ULONG CursorPosY) +{ + CursorX = (CursorPosX < SizeX) ? CursorPosX : SizeX - 1; + CursorY = (CursorPosY < SizeY) ? CursorPosY : SizeY - 1; +} + + +BOOLEAN STDCALL +HalQueryDisplayOwnership(VOID) +{ + return !HalOwnsDisplay; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/dma.c b/reactos/hal/halppc/generic/dma.c new file mode 100644 index 00000000000..a461d845004 --- /dev/null +++ b/reactos/hal/halppc/generic/dma.c @@ -0,0 +1,1950 @@ +/* $Id: dma.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/dma.c + * PURPOSE: DMA functions + * PROGRAMMERS: David Welch (welch@mcmail.com) + * Filip Navara (navaraf@reactos.com) + * UPDATE HISTORY: + * Created 22/05/98 + */ + +/** + * @page DMA Implementation Notes + * + * Concepts: + * + * - Map register + * + * Abstract encapsulation of physically contiguous buffer that resides + * in memory accessible by both the DMA device / controller and the system. + * The map registers are allocated and distributed on demand and are + * scarce resource. + * + * The actual use of map registers is to allow transfers from/to buffer + * located in physical memory at address inaccessible by the DMA device / + * controller directly. For such transfers the map register buffers + * are used as intermediate data storage. + * + * - Master adapter + * + * A container for map registers (typically corresponding to one physical + * bus connection type). There can be master adapters for 24-bit address + * ranges, 32-bit address ranges, etc. Every time a new DMA adapter is + * created it's associated with a corresponding master adapter that + * is used for any map register allocation requests. + * + * - Bus-master / Slave DMA + * + * Slave DMA is term used for DMA transfers done by the system (E)ISA + * controller as opposed to transfers mastered by the device itself + * (hence the name). + * + * For slave DMA special care is taken to actually access the system + * controller and handle the transfers. The relevant code is in + * HalpDmaInitializeEisaAdapter, HalReadDmaCounter, IoFlushAdapterBuffers + * and IoMapTransfer. + * + * Implementation: + * + * - Allocation of map registers + * + * Initial set of map registers is allocated on the system start to + * ensure that low memory won't get filled up later. Additional map + * registers are allocated as needed by HalpGrowMapBuffers. This + * routine is called on two places: + * + * - HalGetAdapter, since we're at PASSIVE_LEVEL and it's known that + * more map registers will probably be needed. + * - IoAllocateAdapterChannel (indirectly using HalpGrowMapBufferWorker + * since we're at DISPATCH_LEVEL and call HalpGrowMapBuffers directly) + * when no more map registers are free. + * + * Note that even if no more map registers can be allocated it's not + * the end of the world. The adapters waiting for free map registers + * are queued in the master adapter's queue and once one driver hands + * back it's map registers (using IoFreeMapRegisters or indirectly using + * the execution routine callback in IoAllocateAdapterChannel) the + * queue gets processed and the map registers are reassigned. + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +static KEVENT HalpDmaLock; +static LIST_ENTRY HalpDmaAdapterList; +static PADAPTER_OBJECT HalpEisaAdapter[8]; +static BOOLEAN HalpEisaDma; +static PADAPTER_OBJECT HalpMasterAdapter; + +static const ULONG_PTR HalpEisaPortPage[8] = { + FIELD_OFFSET(DMA_PAGE, Channel0), + FIELD_OFFSET(DMA_PAGE, Channel1), + FIELD_OFFSET(DMA_PAGE, Channel2), + FIELD_OFFSET(DMA_PAGE, Channel3), + 0, + FIELD_OFFSET(DMA_PAGE, Channel5), + FIELD_OFFSET(DMA_PAGE, Channel6), + FIELD_OFFSET(DMA_PAGE, Channel7) +}; + +static DMA_OPERATIONS HalpDmaOperations = { + sizeof(DMA_OPERATIONS), + (PPUT_DMA_ADAPTER)HalPutDmaAdapter, + (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer, + (PFREE_COMMON_BUFFER)HalFreeCommonBuffer, + NULL, /* Initialized in HalpInitDma() */ + NULL, /* Initialized in HalpInitDma() */ + NULL, /* Initialized in HalpInitDma() */ + NULL, /* Initialized in HalpInitDma() */ + NULL, /* Initialized in HalpInitDma() */ + (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment, + (PREAD_DMA_COUNTER)HalReadDmaCounter, + /* FIXME: Implement the S/G funtions. */ + NULL /*(PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList*/, + NULL /*(PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList*/, + NULL /*(PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize*/, + NULL /*(PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList*/, + NULL /*(PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList*/ +}; + +#define MAX_MAP_REGISTERS 64 + +#define TAG_DMA TAG('D','M','A',' ') + +/* FUNCTIONS *****************************************************************/ + +VOID +HalpInitDma(VOID) +{ + /* + * Initialize the DMA Operation table + */ + HalpDmaOperations.AllocateAdapterChannel = (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel; + HalpDmaOperations.FlushAdapterBuffers = (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers; + HalpDmaOperations.FreeAdapterChannel = (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel; + HalpDmaOperations.FreeMapRegisters = (PFREE_MAP_REGISTERS)IoFreeMapRegisters; + HalpDmaOperations.MapTransfer = (PMAP_TRANSFER)IoMapTransfer; + + /* + * Check if Extended DMA is available. We're just going to do a random + * read and write. + */ + + WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2), 0x2A); + if (READ_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2)) == 0x2A) + HalpEisaDma = TRUE; + + /* + * Intialize all the global variables and allocate master adapter with + * first map buffers. + */ + + InitializeListHead(&HalpDmaAdapterList); + KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE); + + HalpMasterAdapter = HalpDmaAllocateMasterAdapter(); + + /* + * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's + * used by IoGetDmaAdapter in the kernel. + */ + + HalGetDmaAdapter = HalpGetDmaAdapter; +} + +/** + * @name HalpGetAdapterMaximumPhysicalAddress + * + * Get the maximum physical address acceptable by the device represented + * by the passed DMA adapter. + */ + +PHYSICAL_ADDRESS STDCALL +HalpGetAdapterMaximumPhysicalAddress( + IN PADAPTER_OBJECT AdapterObject) +{ + PHYSICAL_ADDRESS HighestAddress; + + if (AdapterObject->MasterDevice) + { + if (AdapterObject->Dma64BitAddresses) + { + HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL; + return HighestAddress; + } + else if (AdapterObject->Dma32BitAddresses) + { + HighestAddress.QuadPart = 0xFFFFFFFF; + return HighestAddress; + } + } + + HighestAddress.QuadPart = 0xFFFFFF; + return HighestAddress; +} + +/** + * @name HalpGrowMapBuffers + * + * Allocate initial, or additional, map buffers for DMA master adapter. + * + * @param MasterAdapter + * DMA master adapter to allocate buffers for. + * @param SizeOfMapBuffers + * Size of the map buffers to allocate (not including the size + * already allocated). + */ + +BOOLEAN STDCALL +HalpGrowMapBuffers( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG SizeOfMapBuffers) +{ + PVOID VirtualAddress; + PHYSICAL_ADDRESS PhysicalAddress; + PHYSICAL_ADDRESS HighestAcceptableAddress; + PHYSICAL_ADDRESS LowestAcceptableAddress; + PHYSICAL_ADDRESS BoundryAddressMultiple; + KIRQL OldIrql; + ULONG MapRegisterCount; + + /* FIXME: Check if enough map register slots are available. */ + + MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers); + + /* + * Allocate memory for the new map registers. For 32-bit adapters we use + * two passes in order not to waste scare resource (low memory). + */ + + HighestAcceptableAddress = + HalpGetAdapterMaximumPhysicalAddress(AdapterObject); + LowestAcceptableAddress.HighPart = 0; + LowestAcceptableAddress.LowPart = + HighestAcceptableAddress.LowPart == 0xFFFFFFFF ? 0x1000000 : 0; + BoundryAddressMultiple.QuadPart = 0; + + VirtualAddress = MmAllocateContiguousMemorySpecifyCache( + MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress, + HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached); + + if (VirtualAddress == NULL && LowestAcceptableAddress.LowPart != 0) + { + LowestAcceptableAddress.LowPart = 0; + VirtualAddress = MmAllocateContiguousMemorySpecifyCache( + MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress, + HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached); + } + + if (VirtualAddress == NULL) + return FALSE; + + PhysicalAddress = MmGetPhysicalAddress(VirtualAddress); + + /* + * All the following must be done with the master adapter lock held + * to prevent corruption. + */ + + OldIrql = KfAcquireSpinLock(&AdapterObject->SpinLock); + + /* + * Setup map register entries for the buffer allocated. Each entry has + * a virtual and physical address and corresponds to PAGE_SIZE large + * buffer. + */ + + if (MapRegisterCount > 0) + { + PROS_MAP_REGISTER_ENTRY CurrentEntry, PreviousEntry; + + CurrentEntry = AdapterObject->MapRegisterBase + + AdapterObject->NumberOfMapRegisters; + do + { + /* + * Leave one entry free for every non-contiguous memory region + * in the map register bitmap. This ensures that we can search + * using RtlFindClearBits for contiguous map register regions. + * + * Also for non-EISA DMA leave one free entry for every 64Kb + * break, because the DMA controller can handle only coniguous + * 64Kb regions. + */ + + if (CurrentEntry != AdapterObject->MapRegisterBase) + { + PreviousEntry = CurrentEntry - 1; + if (PreviousEntry->PhysicalAddress.LowPart + PAGE_SIZE == + PhysicalAddress.LowPart) + { + if (!HalpEisaDma) + { + if ((PreviousEntry->PhysicalAddress.LowPart ^ + PhysicalAddress.LowPart) & 0xFFFF0000) + { + CurrentEntry++; + AdapterObject->NumberOfMapRegisters++; + } + } + } + else + { + CurrentEntry++; + AdapterObject->NumberOfMapRegisters++; + } + } + + RtlClearBit(AdapterObject->MapRegisters, + CurrentEntry - AdapterObject->MapRegisterBase); + CurrentEntry->VirtualAddress = VirtualAddress; + CurrentEntry->PhysicalAddress = PhysicalAddress; + + PhysicalAddress.LowPart += PAGE_SIZE; + VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); + + CurrentEntry++; + AdapterObject->NumberOfMapRegisters++; + MapRegisterCount--; + } + while (MapRegisterCount != 0); + } + + KfReleaseSpinLock(&AdapterObject->SpinLock, OldIrql); + + return TRUE; +} + +/** + * @name HalpDmaAllocateMasterAdapter + * + * Helper routine to allocate and initialize master adapter object and it's + * associated map register buffers. + * + * @see HalpInitDma + */ + +PADAPTER_OBJECT STDCALL +HalpDmaAllocateMasterAdapter(VOID) +{ + PADAPTER_OBJECT MasterAdapter; + ULONG Size, SizeOfBitmap; + + SizeOfBitmap = MAX_MAP_REGISTERS; + Size = sizeof(ADAPTER_OBJECT); + Size += sizeof(RTL_BITMAP); + Size += (SizeOfBitmap + 7) >> 3; + + MasterAdapter = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_DMA); + if (MasterAdapter == NULL) + return NULL; + + RtlZeroMemory(MasterAdapter, Size); + + KeInitializeSpinLock(&MasterAdapter->SpinLock); + InitializeListHead(&MasterAdapter->AdapterQueue); + + MasterAdapter->MapRegisters = (PVOID)(MasterAdapter + 1); + RtlInitializeBitMap( + MasterAdapter->MapRegisters, + (PULONG)(MasterAdapter->MapRegisters + 1), + SizeOfBitmap); + RtlSetAllBits(MasterAdapter->MapRegisters); + MasterAdapter->NumberOfMapRegisters = 0; + MasterAdapter->CommittedMapRegisters = 0; + + MasterAdapter->MapRegisterBase = ExAllocatePoolWithTag( + NonPagedPool, + SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY), + TAG_DMA); + if (MasterAdapter->MapRegisterBase == NULL) + { + ExFreePool(MasterAdapter); + return NULL; + } + + RtlZeroMemory(MasterAdapter->MapRegisterBase, + SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY)); + if (!HalpGrowMapBuffers(MasterAdapter, 0x10000)) + { + ExFreePool(MasterAdapter); + return NULL; + } + + return MasterAdapter; +} + +/** + * @name HalpDmaAllocateChildAdapter + * + * Helper routine of HalGetAdapter. Allocate child adapter object and + * fill out some basic fields. + * + * @see HalGetAdapter + */ + +PADAPTER_OBJECT STDCALL +HalpDmaAllocateChildAdapter( + ULONG NumberOfMapRegisters, + PDEVICE_DESCRIPTION DeviceDescription) +{ + PADAPTER_OBJECT AdapterObject; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE Handle; + + InitializeObjectAttributes( + &ObjectAttributes, + NULL, + OBJ_KERNEL_HANDLE | OBJ_PERMANENT, + NULL, + NULL); + + Status = ObCreateObject( + KernelMode, + IoAdapterObjectType, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(ADAPTER_OBJECT), + 0, + 0, + (PVOID)&AdapterObject); + if (!NT_SUCCESS(Status)) + return NULL; + + Status = ObReferenceObjectByPointer( + AdapterObject, + FILE_READ_DATA | FILE_WRITE_DATA, + IoAdapterObjectType, + KernelMode); + if (!NT_SUCCESS(Status)) + return NULL; + + RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT)); + + Status = ObInsertObject( + AdapterObject, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + NULL, + &Handle); + if (!NT_SUCCESS(Status)) + return NULL; + + ZwClose(Handle); + + AdapterObject->DmaHeader.Version = DeviceDescription->Version; + AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT); + AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations; + AdapterObject->MapRegistersPerChannel = 1; + AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; + AdapterObject->ChannelNumber = 0xFF; + AdapterObject->MasterAdapter = HalpMasterAdapter; + KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue); + + return AdapterObject; +} + +/** + * @name HalpDmaInitializeEisaAdapter + * + * Setup DMA modes and extended modes for (E)ISA DMA adapter object. + */ + +BOOLEAN STDCALL +HalpDmaInitializeEisaAdapter( + PADAPTER_OBJECT AdapterObject, + PDEVICE_DESCRIPTION DeviceDescription) +{ + UCHAR Controller; + DMA_MODE DmaMode = {{0 }}; + DMA_EXTENDED_MODE ExtendedMode = {{ 0 }}; + PVOID AdapterBaseVa; + + Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1; + + if (Controller == 1) + AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController1); + else + AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController2); + + AdapterObject->AdapterNumber = Controller; + AdapterObject->ChannelNumber = DeviceDescription->DmaChannel & 3; + AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel]; + AdapterObject->Width16Bits = FALSE; + AdapterObject->AdapterBaseVa = AdapterBaseVa; + + if (HalpEisaDma) + { + ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber; + + switch (DeviceDescription->DmaSpeed) + { + case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break; + case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break; + case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break; + case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break; + default: + return FALSE; + } + + switch (DeviceDescription->DmaWidth) + { + case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break; + case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break; + case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break; + default: + return FALSE; + } + + if (Controller == 1) + WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1), + ExtendedMode.Byte); + else + WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2), + ExtendedMode.Byte); + } + else + { + /* + * Validate setup for non-busmaster DMA adapter. Secondary controller + * supports only 16-bit transfers and main controller supports only + * 8-bit transfers. Anything else is invalid. + */ + + if (!DeviceDescription->Master) + { + if (Controller == 2 && DeviceDescription->DmaWidth == Width16Bits) + AdapterObject->Width16Bits = TRUE; + else if (Controller != 1 || DeviceDescription->DmaWidth != Width8Bits) + return FALSE; + } + } + + DmaMode.Channel = AdapterObject->ChannelNumber; + DmaMode.AutoInitialize = DeviceDescription->AutoInitialize; + + /* + * Set the DMA request mode. + * + * For (E)ISA bus master devices just unmask (enable) the DMA channel + * and set it to cascade mode. Otherwise just select the right one + * bases on the passed device description. + */ + + if (DeviceDescription->Master) + { + DmaMode.RequestMode = CASCADE_REQUEST_MODE; + if (Controller == 1) + { + /* Set the Request Data */ + WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode, + DmaMode.Byte); + /* Unmask DMA Channel */ + WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask, + AdapterObject->ChannelNumber | DMA_CLEARMASK); + } else { + /* Set the Request Data */ + WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode, + DmaMode.Byte); + /* Unmask DMA Channel */ + WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask, + AdapterObject->ChannelNumber | DMA_CLEARMASK); + } + } + else + { + if (DeviceDescription->DemandMode) + DmaMode.RequestMode = DEMAND_REQUEST_MODE; + else + DmaMode.RequestMode = SINGLE_REQUEST_MODE; + } + + AdapterObject->AdapterMode = DmaMode; + + return TRUE; +} + +/** + * @name HalGetAdapter + * + * Allocate an adapter object for DMA device. + * + * @param DeviceDescription + * Structure describing the attributes of the device. + * @param NumberOfMapRegisters + * On return filled with the maximum number of map registers the + * device driver can allocate for DMA transfer operations. + * + * @return The DMA adapter on success, NULL otherwise. + * + * @implemented + */ + +PADAPTER_OBJECT STDCALL +HalGetAdapter( + PDEVICE_DESCRIPTION DeviceDescription, + PULONG NumberOfMapRegisters) +{ + PADAPTER_OBJECT AdapterObject = NULL; + PADAPTER_OBJECT MasterAdapter; + BOOLEAN EisaAdapter; + ULONG MapRegisters; + ULONG MaximumLength; + + /* Validate parameters in device description */ + if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2) + return NULL; + + /* + * See if we're going to use ISA/EISA DMA adapter. These adapters are + * special since they're reused. + * + * Also note that we check for channel number since there are only 8 DMA + * channels on ISA, so any request above this requires new adapter. + */ + + if (DeviceDescription->InterfaceType == Isa || !DeviceDescription->Master) + { + if (DeviceDescription->InterfaceType == Isa && + DeviceDescription->DmaChannel >= 8) + EisaAdapter = FALSE; + else + EisaAdapter = TRUE; + } + else + { + EisaAdapter = FALSE; + } + + /* + * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used + * for cascading the controllers and it's not available for software use. + */ + + if (EisaAdapter && DeviceDescription->DmaChannel == 4) + return NULL; + + /* + * Calculate the number of map registers. + * + * - For EISA and PCI scatter/gather no map registers are needed. + * - For ISA slave scatter/gather one map register is needed. + * - For all other cases the number of map registers depends on + * DeviceDescription->MaximumLength. + */ + + MaximumLength = DeviceDescription->MaximumLength & MAXLONG; + if (DeviceDescription->ScatterGather && + (DeviceDescription->InterfaceType == Eisa || + DeviceDescription->InterfaceType == PCIBus)) + { + MapRegisters = 0; + } + else if (DeviceDescription->ScatterGather && + !DeviceDescription->Master) + { + MapRegisters = 1; + } + else + { + /* + * In the equation below the additional map register added by + * the "+1" accounts for the case when a transfer does not start + * at a page-aligned address. + */ + MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1; + if (MapRegisters > 16) + MapRegisters = 16; + } + + /* + * Acquire the DMA lock that is used to protect adapter lists and + * EISA adapter array. + */ + + KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, + FALSE, NULL); + + /* + * Now we must get ahold of the adapter object. For first eight ISA/EISA + * channels there are static adapter objects that are reused and updated + * on succesive HalGetAdapter calls. In other cases a new adapter object + * is always created and it's to the DMA adapter list (HalpDmaAdapterList). + */ + + if (EisaAdapter) + { + AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel]; + if (AdapterObject != NULL) + { + if (AdapterObject->NeedsMapRegisters && + MapRegisters > AdapterObject->MapRegistersPerChannel) + AdapterObject->MapRegistersPerChannel = MapRegisters; + } + } + + if (AdapterObject == NULL) + { + AdapterObject = HalpDmaAllocateChildAdapter( + MapRegisters, DeviceDescription); + if (AdapterObject == NULL) + { + KeSetEvent(&HalpDmaLock, 0, 0); + return NULL; + } + + if (EisaAdapter) + { + HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject; + } + + if (MapRegisters > 0) + { + AdapterObject->NeedsMapRegisters = TRUE; + MasterAdapter = HalpMasterAdapter; + AdapterObject->MapRegistersPerChannel = MapRegisters; + + /* + * FIXME: Verify that the following makes sense. Actually + * MasterAdapter->NumberOfMapRegisters contains even the number + * of gaps, so this will not work correctly all the time. It + * doesn't matter much since it's only optimization to avoid + * queuing work items in HalAllocateAdapterChannel. + */ + + MasterAdapter->CommittedMapRegisters += MapRegisters; + if (MasterAdapter->CommittedMapRegisters > MasterAdapter->NumberOfMapRegisters) + HalpGrowMapBuffers(MasterAdapter, 0x10000); + } + else + { + AdapterObject->NeedsMapRegisters = FALSE; + if (DeviceDescription->Master) + AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1; + else + AdapterObject->MapRegistersPerChannel = 1; + } + } + + if (!EisaAdapter) + InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList); + + /* + * Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will + * no longer be touched, so we don't need it. + */ + + KeSetEvent(&HalpDmaLock, 0, 0); + + /* + * Setup the values in the adapter object that are common for all + * types of buses. + */ + + if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1) + AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount; + else + AdapterObject->IgnoreCount = 0; + + AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; + AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses; + AdapterObject->ScatterGather = DeviceDescription->ScatterGather; + AdapterObject->MasterDevice = DeviceDescription->Master; + *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel; + + /* + * For non-(E)ISA adapters we have already done all the work. On the + * other hand for (E)ISA adapters we must still setup the DMA modes + * and prepare the controller. + */ + + if (EisaAdapter) + { + if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription)) + { + ObfDereferenceObject(AdapterObject); + return NULL; + } + } + + return AdapterObject; +} + +/** + * @name HalpGetDmaAdapter + * + * Internal routine to allocate PnP DMA adapter object. It's exported through + * HalDispatchTable and used by IoGetDmaAdapter. + * + * @see HalGetAdapter + */ + +PDMA_ADAPTER STDCALL +HalpGetDmaAdapter( + IN PVOID Context, + IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters) +{ + return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader; +} + +/** + * @name HalPutDmaAdapter + * + * Internal routine to free DMA adapter and resources for reuse. It's exported + * using the DMA_OPERATIONS interface by HalGetAdapter. + * + * @see HalGetAdapter + */ + +VOID STDCALL +HalPutDmaAdapter( + PADAPTER_OBJECT AdapterObject) +{ + if (AdapterObject->ChannelNumber == 0xFF) + { + KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, + FALSE, NULL); + RemoveEntryList(&AdapterObject->AdapterList); + KeSetEvent(&HalpDmaLock, 0, 0); + } + + ObfDereferenceObject(AdapterObject); +} + +/** + * @name HalAllocateCommonBuffer + * + * Allocates memory that is visible to both the processor(s) and the DMA + * device. + * + * @param AdapterObject + * Adapter object representing the bus master or system dma controller. + * @param Length + * Number of bytes to allocate. + * @param LogicalAddress + * Logical address the driver can use to access the buffer. + * @param CacheEnabled + * Specifies if the memory can be cached. + * + * @return The base virtual address of the memory allocated or NULL on failure. + * + * @remarks + * On real NT x86 systems the CacheEnabled parameter is ignored, we honour + * it. If it proves to cause problems change it. + * + * @see HalFreeCommonBuffer + * + * @implemented + */ + +PVOID STDCALL +HalAllocateCommonBuffer( + PADAPTER_OBJECT AdapterObject, + ULONG Length, + PPHYSICAL_ADDRESS LogicalAddress, + BOOLEAN CacheEnabled) +{ + PHYSICAL_ADDRESS LowestAcceptableAddress; + PHYSICAL_ADDRESS HighestAcceptableAddress; + PHYSICAL_ADDRESS BoundryAddressMultiple; + PVOID VirtualAddress; + + LowestAcceptableAddress.QuadPart = 0; + HighestAcceptableAddress = + HalpGetAdapterMaximumPhysicalAddress(AdapterObject); + BoundryAddressMultiple.QuadPart = 0; + + /* + * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For + * slave DMA devices the 64Kb boundary mustn't be crossed since the + * controller wouldn't be able to handle it. + */ + + if (AdapterObject->MasterDevice) + BoundryAddressMultiple.HighPart = 1; + else + BoundryAddressMultiple.LowPart = 0x10000; + + VirtualAddress = MmAllocateContiguousMemorySpecifyCache( + Length, LowestAcceptableAddress, HighestAcceptableAddress, + BoundryAddressMultiple, CacheEnabled ? MmCached : MmNonCached); + if (VirtualAddress == NULL) + return NULL; + + *LogicalAddress = MmGetPhysicalAddress(VirtualAddress); + + return VirtualAddress; +} + +/** + * @name HalFreeCommonBuffer + * + * Free common buffer allocated with HalAllocateCommonBuffer. + * + * @see HalAllocateCommonBuffer + * + * @implemented + */ + +VOID STDCALL +HalFreeCommonBuffer( + PADAPTER_OBJECT AdapterObject, + ULONG Length, + PHYSICAL_ADDRESS LogicalAddress, + PVOID VirtualAddress, + BOOLEAN CacheEnabled) +{ + MmFreeContiguousMemory(VirtualAddress); +} + +/** + * @name HalpDmaGetDmaAlignment + * + * Internal routine to return the DMA alignment requirement. It's exported + * using the DMA_OPERATIONS interface by HalGetAdapter. + * + * @see HalGetAdapter + */ + +ULONG STDCALL +HalpDmaGetDmaAlignment( + PADAPTER_OBJECT AdapterObject) +{ + return 1; +} + +/* + * @name HalReadDmaCounter + * + * Read DMA operation progress counter. + * + * @implemented + */ + +ULONG STDCALL +HalReadDmaCounter( + PADAPTER_OBJECT AdapterObject) +{ + KIRQL OldIrql; + ULONG Count, OldCount; + + ASSERT(!AdapterObject->MasterDevice); + + /* + * Acquire the master adapter lock since we're going to mess with the + * system DMA controller registers and we really don't want anyone + * to do the same at the same time. + */ + + KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql); + + /* Send the request to the specific controller. */ + if (AdapterObject->AdapterNumber == 1) + { + PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; + + Count = 0xffff00; + do + { + OldCount = Count; + /* Send Reset */ + WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); + /* Read Count */ + Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount); + Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount) << 8; + } + while (0xffff00 & (OldCount ^ Count)); + } + else + { + PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; + + Count = 0xffff00; + do + { + OldCount = Count; + /* Send Reset */ + WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); + /* Read Count */ + Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount); + Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount) << 8; + } + while (0xffff00 & (OldCount ^ Count)); + } + + KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); + + Count++; + Count &= 0xffff; + if (AdapterObject->Width16Bits) + Count *= 2; + + return Count; +} + +/** + * @name HalpGrowMapBufferWorker + * + * Helper routine of HalAllocateAdapterChannel for allocating map registers + * at PASSIVE_LEVEL in work item. + */ + +VOID STDCALL +HalpGrowMapBufferWorker(PVOID DeferredContext) +{ + PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext; + KIRQL OldIrql; + BOOLEAN Succeeded; + + /* + * Try to allocate new map registers for the adapter. + * + * NOTE: The NT implementation actually tries to allocate more map + * registers than needed as an optimization. + */ + + KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, + FALSE, NULL); + Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter, + WorkItem->NumberOfMapRegisters); + KeSetEvent(&HalpDmaLock, 0, 0); + + if (Succeeded) + { + /* + * Flush the adapter queue now that new map registers are ready. The + * easiest way to do that is to call IoFreeMapRegisters to not free + * any registers. Note that we use the magic (PVOID)2 map register + * base to bypass the parameter checking. + */ + + OldIrql = KfRaiseIrql(DISPATCH_LEVEL); + IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0); + KfLowerIrql(OldIrql); + } + + ExFreePool(WorkItem); +} + +/** + * @name HalAllocateAdapterChannel + * + * Setup map registers for an adapter object. + * + * @param AdapterObject + * Pointer to an ADAPTER_OBJECT to set up. + * @param WaitContextBlock + * Context block to be used with ExecutionRoutine. + * @param NumberOfMapRegisters + * Number of map registers requested. + * @param ExecutionRoutine + * Callback to call when map registers are allocated. + * + * @return + * If not enough map registers can be allocated then + * STATUS_INSUFFICIENT_RESOURCES is returned. If the function + * succeeds or the callback is queued for later delivering then + * STATUS_SUCCESS is returned. + * + * @see IoFreeAdapterChannel + * + * @implemented + */ + +NTSTATUS STDCALL +HalAllocateAdapterChannel( + PADAPTER_OBJECT AdapterObject, + PWAIT_CONTEXT_BLOCK WaitContextBlock, + ULONG NumberOfMapRegisters, + PDRIVER_CONTROL ExecutionRoutine) +{ + PADAPTER_OBJECT MasterAdapter; + PGROW_WORK_ITEM WorkItem; + ULONG Index = ~0; + ULONG Result; + KIRQL OldIrql; + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + /* Set up the wait context block in case we can't run right away. */ + WaitContextBlock->DeviceRoutine = ExecutionRoutine; + WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters; + + /* Returns true if queued, else returns false and sets the queue to busy */ + if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, &WaitContextBlock->WaitQueueEntry)) + return STATUS_SUCCESS; + + MasterAdapter = AdapterObject->MasterAdapter; + + AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; + AdapterObject->CurrentWcb = WaitContextBlock; + + if (NumberOfMapRegisters && AdapterObject->NeedsMapRegisters) + { + if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) + { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* + * Get the map registers. This is partly complicated by the fact + * that new map registers can only be allocated at PASSIVE_LEVEL + * and we're currently at DISPATCH_LEVEL. The following code has + * two code paths: + * + * - If there is no adapter queued for map register allocation, + * try to see if enough contiguous map registers are present. + * In case they're we can just get them and proceed further. + * + * - If some adapter is already present in the queue we must + * respect the order of adapters asking for map registers and + * so the fast case described above can't take place. + * This case is also entered if not enough coniguous map + * registers are present. + * + * A work queue item is allocated and queued, the adapter is + * also queued into the master adapter queue. The worker + * routine does the job of allocating the map registers at + * PASSIVE_LEVEL and calling the ExecutionRoutine. + */ + + OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); + + if (IsListEmpty(&MasterAdapter->AdapterQueue)) + { + Index = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, NumberOfMapRegisters, 0); + if (Index != ~0) + { + AdapterObject->MapRegisterBase = + MasterAdapter->MapRegisterBase + Index; + if (!AdapterObject->ScatterGather) + { + AdapterObject->MapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)( + (ULONG_PTR)AdapterObject->MapRegisterBase | + MAP_BASE_SW_SG); + } + } + } + + if (Index == ~0) + { + WorkItem = ExAllocatePoolWithTag( + NonPagedPool, sizeof(GROW_WORK_ITEM), TAG_DMA); + if (WorkItem == NULL) + { + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); + + ExInitializeWorkItem( + &WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem); + WorkItem->AdapterObject = AdapterObject; + WorkItem->NumberOfMapRegisters = NumberOfMapRegisters; + + ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue); + + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + + return STATUS_SUCCESS; + } + + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + } + else + { + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + AdapterObject->CurrentWcb = WaitContextBlock; + + Result = ExecutionRoutine( + WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp, + AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext); + + /* + * Possible return values: + * + * - KeepObject + * Don't free any resources, the ADAPTER_OBJECT is still in use and + * the caller will call IoFreeAdapterChannel later. + * + * - DeallocateObject + * Deallocate the map registers and release the ADAPTER_OBJECT, so + * someone else can use it. + * + * - DeallocateObjectKeepRegisters + * Release the ADAPTER_OBJECT, but hang on to the map registers. The + * client will later call IoFreeMapRegisters. + * + * NOTE: + * IoFreeAdapterChannel runs the queue, so it must be called unless + * the adapter object is not to be freed. + */ + + if (Result == DeallocateObject) + { + IoFreeAdapterChannel(AdapterObject); + } + else if (Result == DeallocateObjectKeepRegisters) + { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + } + + return STATUS_SUCCESS; +} + +/** + * @name IoFreeAdapterChannel + * + * Free DMA resources allocated by IoAllocateAdapterChannel. + * + * @param AdapterObject + * Adapter object with resources to free. + * + * @remarks + * This function releases map registers registers assigned to the DMA + * adapter. After releasing the adapter, it checks the adapter's queue + * and runs each queued device object in series until the queue is + * empty. This is the only way the device queue is emptied. + * + * @see IoAllocateAdapterChannel + * + * @implemented + */ + +VOID STDCALL +IoFreeAdapterChannel( + PADAPTER_OBJECT AdapterObject) +{ + PADAPTER_OBJECT MasterAdapter; + PKDEVICE_QUEUE_ENTRY DeviceQueueEntry; + PWAIT_CONTEXT_BLOCK WaitContextBlock; + ULONG Index = ~0; + ULONG Result; + KIRQL OldIrql; + + MasterAdapter = AdapterObject->MasterAdapter; + + for (;;) + { + /* + * To keep map registers, call here with AdapterObject-> + * NumberOfMapRegisters set to zero. This trick is used in + * HalAllocateAdapterChannel for example. + */ + if (AdapterObject->NumberOfMapRegisters) + { + IoFreeMapRegisters( + AdapterObject, + AdapterObject->MapRegisterBase, + AdapterObject->NumberOfMapRegisters); + } + + DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue); + if (DeviceQueueEntry == NULL) + { + break; + } + + WaitContextBlock = CONTAINING_RECORD( + DeviceQueueEntry, + WAIT_CONTEXT_BLOCK, + WaitQueueEntry); + + AdapterObject->CurrentWcb = WaitContextBlock; + AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters; + + if (WaitContextBlock->NumberOfMapRegisters && + AdapterObject->MasterAdapter) + { + OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); + + if (IsListEmpty(&MasterAdapter->AdapterQueue)) + { + Index = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + WaitContextBlock->NumberOfMapRegisters, 0); + if (Index != ~0) + { + AdapterObject->MapRegisterBase = + MasterAdapter->MapRegisterBase + Index; + if (!AdapterObject->ScatterGather) + { + AdapterObject->MapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)( + (ULONG_PTR)AdapterObject->MapRegisterBase | + MAP_BASE_SW_SG); + } + } + } + + if (Index == ~0) + { + InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + break; + } + + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + } + else + { + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + /* Call the adapter control routine. */ + Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)( + WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp, + AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext); + + switch (Result) + { + case KeepObject: + /* + * We're done until the caller manually calls IoFreeAdapterChannel + * or IoFreeMapRegisters. + */ + return; + + case DeallocateObjectKeepRegisters: + /* + * Hide the map registers so they aren't deallocated next time + * around. + */ + AdapterObject->NumberOfMapRegisters = 0; + break; + + default: + break; + } + } +} + +/** + * @name IoFreeMapRegisters + * + * Free map registers reserved by the system for a DMA. + * + * @param AdapterObject + * DMA adapter to free map registers on. + * @param MapRegisterBase + * Handle to map registers to free. + * @param NumberOfRegisters + * Number of map registers to be freed. + * + * @implemented + */ + +VOID STDCALL +IoFreeMapRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN PVOID MapRegisterBase, + IN ULONG NumberOfMapRegisters) +{ + PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; + PLIST_ENTRY ListEntry; + KIRQL OldIrql; + ULONG Index; + ULONG Result; + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + if (MasterAdapter == NULL || MapRegisterBase == NULL) + return; + + OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); + + if (NumberOfMapRegisters != 0) + { + PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; + + RealMapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); + RtlClearBits(MasterAdapter->MapRegisters, + RealMapRegisterBase - MasterAdapter->MapRegisterBase, + NumberOfMapRegisters); + } + + /* + * Now that we freed few map registers it's time to look at the master + * adapter queue and see if there is someone waiting for map registers. + */ + + while (!IsListEmpty(&MasterAdapter->AdapterQueue)) + { + ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue); + AdapterObject = CONTAINING_RECORD( + ListEntry, struct _ADAPTER_OBJECT, AdapterQueue); + + Index = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + AdapterObject->NumberOfMapRegisters, + MasterAdapter->NumberOfMapRegisters); + if (Index == ~0) + { + InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry); + break; + } + + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + + AdapterObject->MapRegisterBase = + MasterAdapter->MapRegisterBase + Index; + if (!AdapterObject->ScatterGather) + { + AdapterObject->MapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)( + (ULONG_PTR)AdapterObject->MapRegisterBase | + MAP_BASE_SW_SG); + } + + Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)( + AdapterObject->CurrentWcb->DeviceObject, + AdapterObject->CurrentWcb->CurrentIrp, + AdapterObject->MapRegisterBase, + AdapterObject->CurrentWcb->DeviceContext); + + switch (Result) + { + case DeallocateObjectKeepRegisters: + AdapterObject->NumberOfMapRegisters = 0; + /* fall through */ + + case DeallocateObject: + if (AdapterObject->NumberOfMapRegisters) + { + OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); + RtlClearBits(MasterAdapter->MapRegisters, + AdapterObject->MapRegisterBase - + MasterAdapter->MapRegisterBase, + AdapterObject->NumberOfMapRegisters); + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + } + IoFreeAdapterChannel(AdapterObject); + break; + + default: + break; + } + + OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); + } + + KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); +} + +/** + * @name HalpCopyBufferMap + * + * Helper function for copying data from/to map register buffers. + * + * @see IoFlushAdapterBuffers, IoMapTransfer + */ + +VOID STDCALL +HalpCopyBufferMap( + PMDL Mdl, + PROS_MAP_REGISTER_ENTRY MapRegisterBase, + PVOID CurrentVa, + ULONG Length, + BOOLEAN WriteToDevice) +{ + ULONG CurrentLength; + ULONG_PTR CurrentAddress; + ULONG ByteOffset; + PVOID VirtualAddress; + + VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority); + if (VirtualAddress == NULL) + { + /* + * NOTE: On real NT a mechanism with reserved pages is implemented + * to handle this case in a slow, but graceful non-fatal way. + */ + /* FIXME: The correct bug check code isn't defined. */ + /* KEBUGCHECKEX(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0); */ + KEBUGCHECK(0); + } + + CurrentAddress = (ULONG_PTR)VirtualAddress + + (ULONG_PTR)CurrentVa - + (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); + + while (Length > 0) + { + ByteOffset = BYTE_OFFSET(CurrentAddress); + CurrentLength = PAGE_SIZE - ByteOffset; + if (CurrentLength > Length) + CurrentLength = Length; + + if (WriteToDevice) + { + RtlCopyMemory( + (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), + (PVOID)CurrentAddress, + CurrentLength); + } + else + { + RtlCopyMemory( + (PVOID)CurrentAddress, + (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), + CurrentLength); + } + + Length -= CurrentLength; + CurrentAddress += CurrentLength; + MapRegisterBase++; + } +} + +/** + * @name IoFlushAdapterBuffers + * + * Flush any data remaining in the DMA controller's memory into the host + * memory. + * + * @param AdapterObject + * The adapter object to flush. + * @param Mdl + * Original MDL to flush data into. + * @param MapRegisterBase + * Map register base that was just used by IoMapTransfer, etc. + * @param CurrentVa + * Offset into Mdl to be flushed into, same as was passed to + * IoMapTransfer. + * @param Length + * Length of the buffer to be flushed into. + * @param WriteToDevice + * TRUE if it's a write, FALSE if it's a read. + * + * @return TRUE in all cases. + * + * @remarks + * This copies data from the map register-backed buffer to the user's + * target buffer. Data are not in the user buffer until this function + * is called. + * For slave DMA transfers the controller channel is masked effectively + * stopping the current transfer. + * + * @unimplemented. + */ + +BOOLEAN STDCALL +IoFlushAdapterBuffers( + PADAPTER_OBJECT AdapterObject, + PMDL Mdl, + PVOID MapRegisterBase, + PVOID CurrentVa, + ULONG Length, + BOOLEAN WriteToDevice) +{ + BOOLEAN SlaveDma = FALSE; + PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; + + ASSERT_IRQL(DISPATCH_LEVEL); + + if (AdapterObject != NULL && !AdapterObject->MasterDevice) + { + /* Mask out (disable) the DMA channel. */ + if (AdapterObject->AdapterNumber == 1) + { + PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; + WRITE_PORT_UCHAR(&DmaControl1->SingleMask, + AdapterObject->ChannelNumber | DMA_SETMASK); + } + else + { + PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; + WRITE_PORT_UCHAR(&DmaControl2->SingleMask, + AdapterObject->ChannelNumber | DMA_SETMASK); + } + SlaveDma = TRUE; + } + + /* This can happen if the device supports hardware scatter/gather. */ + if (MapRegisterBase == NULL) + return TRUE; + + RealMapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); + + if (!WriteToDevice) + { + if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) + { + if (RealMapRegisterBase->Counter != ~0) + { + if (SlaveDma && !AdapterObject->IgnoreCount) + Length -= HalReadDmaCounter(AdapterObject); + } + + HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE); + } + else + { + /* FIXME: Unimplemented case */ + ASSERT(FALSE); + } + } + + RealMapRegisterBase->Counter = 0; + + return TRUE; +} + +/** + * @name IoMapTransfer + * + * Map a DMA for transfer and do the DMA if it's a slave. + * + * @param AdapterObject + * Adapter object to do the DMA on. Bus-master may pass NULL. + * @param Mdl + * Locked-down user buffer to DMA in to or out of. + * @param MapRegisterBase + * Handle to map registers to use for this dma. + * @param CurrentVa + * Index into Mdl to transfer into/out of. + * @param Length + * Length of transfer. Number of bytes actually transferred on + * output. + * @param WriteToDevice + * TRUE if it's an output DMA, FALSE otherwise. + * + * @return + * A logical address that can be used to program a DMA controller, it's + * not meaningful for slave DMA device. + * + * @remarks + * This function does a copyover to contiguous memory <16MB represented + * by the map registers if needed. If the buffer described by MDL can be + * used as is no copyover is done. + * If it's a slave transfer, this function actually performs it. + * + * @implemented + */ + +PHYSICAL_ADDRESS STDCALL +IoMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN OUT PULONG Length, + IN BOOLEAN WriteToDevice) +{ + PPFN_NUMBER MdlPagesPtr; + PFN_NUMBER MdlPage1, MdlPage2; + ULONG ByteOffset; + ULONG TransferOffset; + ULONG TransferLength; + BOOLEAN UseMapRegisters; + PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; + PHYSICAL_ADDRESS PhysicalAddress; + PHYSICAL_ADDRESS HighestAcceptableAddress; + ULONG Counter; + DMA_MODE AdapterMode; + KIRQL OldIrql; + + /* + * Precalculate some values that are used in all cases. + * + * ByteOffset is offset inside the page at which the transfer starts. + * MdlPagesPtr is pointer inside the MDL page chain at the page where the + * transfer start. + * PhysicalAddress is physical address corresponding to the transfer + * start page and offset. + * TransferLength is the inital length of the transfer, which is reminder + * of the first page. The actual value is calculated below. + * + * Note that all the variables can change during the processing which + * takes place below. These are just initial values. + */ + + ByteOffset = BYTE_OFFSET(CurrentVa); + + MdlPagesPtr = MmGetMdlPfnArray(Mdl); + MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT; + + PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; + PhysicalAddress.QuadPart += ByteOffset; + + TransferLength = PAGE_SIZE - ByteOffset; + + /* + * Special case for bus master adapters with S/G support. We can directly + * use the buffer specified by the MDL, so not much work has to be done. + * + * Just return the passed VA's corresponding physical address and update + * length to the number of physically contiguous bytes found. Also + * pages crossing the 4Gb boundary aren't considered physically contiguous. + */ + + if (MapRegisterBase == NULL) + { + while (TransferLength < *Length) + { + MdlPage1 = *MdlPagesPtr; + MdlPage2 = *(MdlPagesPtr + 1); + if (MdlPage1 + 1 != MdlPage2) + break; + if ((MdlPage1 ^ MdlPage2) & ~0xFFFFF) + break; + TransferLength += PAGE_SIZE; + MdlPagesPtr++; + } + + if (TransferLength < *Length) + *Length = TransferLength; + + return PhysicalAddress; + } + + /* + * The code below applies to slave DMA adapters and bus master adapters + * without hardward S/G support. + */ + + RealMapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); + + /* + * Try to calculate the size of the transfer. We can only transfer + * pages that are physically contiguous and that don't cross the + * 64Kb boundary (this limitation applies only for ISA controllers). + */ + + while (TransferLength < *Length) + { + MdlPage1 = *MdlPagesPtr; + MdlPage2 = *(MdlPagesPtr + 1); + if (MdlPage1 + 1 != MdlPage2) + break; + if (!HalpEisaDma && ((MdlPage1 ^ MdlPage2) & ~0xF)) + break; + TransferLength += PAGE_SIZE; + MdlPagesPtr++; + } + + if (TransferLength > *Length) + TransferLength = *Length; + + /* + * If we're about to simulate software S/G and not all the pages are + * physically contiguous then we must use the map registers to store + * the data and allow the whole transfer to proceed at once. + */ + + if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG && + TransferLength < *Length) + { + UseMapRegisters = TRUE; + PhysicalAddress = RealMapRegisterBase->PhysicalAddress; + PhysicalAddress.QuadPart += ByteOffset; + TransferLength = *Length; + RealMapRegisterBase->Counter = ~0; + Counter = 0; + } + else + { + /* + * This is ordinary DMA transfer, so just update the progress + * counters. These are used by IoFlushAdapterBuffers to track + * the transfer progress. + */ + + UseMapRegisters = FALSE; + Counter = RealMapRegisterBase->Counter; + RealMapRegisterBase->Counter += BYTES_TO_PAGES(ByteOffset + TransferLength); + + /* + * Check if the buffer doesn't exceed the highest physical address + * limit of the device. In that case we must use the map registers to + * store the data. + */ + + HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); + if (PhysicalAddress.QuadPart + TransferLength > + HighestAcceptableAddress.QuadPart) + { + UseMapRegisters = TRUE; + PhysicalAddress = RealMapRegisterBase->PhysicalAddress; + PhysicalAddress.QuadPart += ByteOffset; + if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) + { + RealMapRegisterBase->Counter = ~0; + } + } + } + + /* + * If we decided to use the map registers (see above) and we're about + * to transfer data to the device then copy the buffers into the map + * register memory. + */ + + if (UseMapRegisters && WriteToDevice) + { + HalpCopyBufferMap(Mdl, RealMapRegisterBase + Counter, + CurrentVa, TransferLength, WriteToDevice); + } + + /* + * Return the length of transfer that actually takes place. + */ + + *Length = TransferLength; + + /* + * If we're doing slave (system) DMA then program the (E)ISA controller + * to actually start the transfer. + */ + + if (AdapterObject != NULL && !AdapterObject->MasterDevice) + { + AdapterMode = AdapterObject->AdapterMode; + + if (WriteToDevice) + { + AdapterMode.TransferType = WRITE_TRANSFER; + } + else + { + AdapterMode.TransferType = READ_TRANSFER; + if (AdapterObject->IgnoreCount) + { + RtlZeroMemory((PUCHAR)RealMapRegisterBase[Counter].VirtualAddress + + ByteOffset, TransferLength); + } + } + + TransferOffset = PhysicalAddress.LowPart & 0xFFFF; + if (AdapterObject->Width16Bits) + { + TransferLength >>= 1; + TransferOffset >>= 1; + } + + OldIrql = KfAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock); + + if (AdapterObject->AdapterNumber == 1) + { + PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; + + /* Reset Register */ + WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); + /* Set the Mode */ + WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte); + /* Set the Offset Register */ + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset)); + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset >> 8)); + /* Set the Page Register */ + WRITE_PORT_UCHAR(AdapterObject->PagePort + + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), + (UCHAR)(PhysicalAddress.LowPart >> 16)); + if (HalpEisaDma) + { + WRITE_PORT_UCHAR(AdapterObject->PagePort + + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), + 0); + } + /* Set the Length */ + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)(TransferLength - 1)); + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)((TransferLength - 1) >> 8)); + /* Unmask the Channel */ + WRITE_PORT_UCHAR(&DmaControl1->SingleMask, + AdapterObject->ChannelNumber | DMA_CLEARMASK); + } + else + { + PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; + + /* Reset Register */ + WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); + /* Set the Mode */ + WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte); + /* Set the Offset Register */ + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset)); + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset >> 8)); + /* Set the Page Register */ + WRITE_PORT_UCHAR(AdapterObject->PagePort + + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), + (UCHAR)(PhysicalAddress.u.LowPart >> 16)); + if (HalpEisaDma) + { + WRITE_PORT_UCHAR(AdapterObject->PagePort + + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), + 0); + } + /* Set the Length */ + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)(TransferLength - 1)); + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)((TransferLength - 1) >> 8)); + /* Unmask the Channel */ + WRITE_PORT_UCHAR(&DmaControl2->SingleMask, + AdapterObject->ChannelNumber | DMA_CLEARMASK); + } + + KfReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); + } + + /* + * Return physical address of the buffer with data that is used for the + * transfer. It can either point inside the Mdl that was passed by the + * caller or into the map registers if the Mdl buffer can't be used + * directly. + */ + + return PhysicalAddress; +} + +/** + * @name HalFlushCommonBuffer + * + * @implemented + */ + +BOOLEAN STDCALL +HalFlushCommonBuffer( + ULONG Unknown1, + ULONG Unknown2, + ULONG Unknown3, + ULONG Unknown4, + ULONG Unknown5) +{ + return TRUE; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/drive.c b/reactos/hal/halppc/generic/drive.c new file mode 100644 index 00000000000..281e0e121c3 --- /dev/null +++ b/reactos/hal/halppc/generic/drive.c @@ -0,0 +1,33 @@ +/* $Id: drive.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/x86/drive.c + * PURPOSE: Drive letter assignment + * PROGRAMMER: + * UPDATE HISTORY: + * 2000-03-25 + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +VOID STDCALL +IoAssignDriveLetters(IN struct _LOADER_PARAMETER_BLOCK *LoaderBlock, + IN PSTRING NtDeviceName, + OUT PUCHAR NtSystemPath, + OUT PSTRING NtSystemPathString) +{ + /* FIXME FIXME FIXME FUCK SOMEONE FIXME*/ + HalIoAssignDriveLetters(NULL, + NtDeviceName, + NtSystemPath, + NtSystemPathString); +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/enum.c b/reactos/hal/halppc/generic/enum.c new file mode 100644 index 00000000000..af8b06d4a87 --- /dev/null +++ b/reactos/hal/halppc/generic/enum.c @@ -0,0 +1,23 @@ +/* $Id: enum.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/enum.c + * PURPOSE: Motherboard device enumerator + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * Created 01/05/2001 + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +VOID +HalpStartEnumerator (VOID) +{ +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/fmutex.c b/reactos/hal/halppc/generic/fmutex.c new file mode 100644 index 00000000000..a7624edb748 --- /dev/null +++ b/reactos/hal/halppc/generic/fmutex.c @@ -0,0 +1,101 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS HAL + * FILE: ntoskrnl/hal/x86/fmutex.c + * PURPOSE: Deprecated HAL Fast Mutex + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* + * NOTE: Even HAL itself has #defines to use the Exi* APIs inside NTOSKRNL. + * These are only exported here for compatibility with really old + * drivers. Also note that in theory, these can be made much faster + * by using assembly and inlining all the operations, including + * raising and lowering irql. + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +#undef ExAcquireFastMutex +#undef ExReleaseFastMutex +#undef ExTryToAcquireFastMutex + +/* FUNCTIONS *****************************************************************/ + +VOID +FASTCALL +ExAcquireFastMutex(PFAST_MUTEX FastMutex) +{ + KIRQL OldIrql; + + /* Raise IRQL to APC */ + OldIrql = KfRaiseIrql(APC_LEVEL); + + /* Decrease the count */ + if (InterlockedDecrement(&FastMutex->Count)) + { + /* Someone is still holding it, use slow path */ + FastMutex->Contention++; + KeWaitForSingleObject(&FastMutex->Gate, + WrExecutive, + KernelMode, + FALSE, + NULL); + } + + /* Set the owner and IRQL */ + FastMutex->Owner = KeGetCurrentThread(); + FastMutex->OldIrql = OldIrql; +} + +VOID +FASTCALL +ExReleaseFastMutex(PFAST_MUTEX FastMutex) +{ + KIRQL OldIrql; + + /* Erase the owner */ + FastMutex->Owner = (PVOID)1; + OldIrql = FastMutex->OldIrql; + + /* Increase the count */ + if (InterlockedIncrement(&FastMutex->Count) <= 0) + { + /* Someone was waiting for it, signal the waiter */ + KeSetEventBoostPriority(&FastMutex->Gate, IO_NO_INCREMENT); + } + + /* Lower IRQL back */ + KfLowerIrql(OldIrql); +} + +BOOLEAN +FASTCALL +ExTryToAcquireFastMutex(PFAST_MUTEX FastMutex) +{ + KIRQL OldIrql; + + /* Raise to APC_LEVEL */ + OldIrql = KfRaiseIrql(APC_LEVEL); + + /* Check if we can quickly acquire it */ + if (InterlockedCompareExchange(&FastMutex->Count, 0, 1) == 1) + { + /* We have, set us as owners */ + FastMutex->Owner = KeGetCurrentThread(); + FastMutex->OldIrql = OldIrql; + return TRUE; + } + else + { + /* Acquire attempt failed */ + KfLowerIrql(OldIrql); + return FALSE; + } +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/generic.rbuild b/reactos/hal/halppc/generic/generic.rbuild new file mode 100644 index 00000000000..ab14f754594 --- /dev/null +++ b/reactos/hal/halppc/generic/generic.rbuild @@ -0,0 +1,26 @@ + + ../include + include + + + + beep.c + bus.c + dma.c + drive.c + enum.c + fmutex.c + halinit.c + isa.c + kdbg.c + mca.c + misc.c + pci.c + portio.c + reboot.c + sysbus.c + sysinfo.c + time.c + timer.c + ../include/hal.h + diff --git a/reactos/hal/halppc/generic/halinit.c b/reactos/hal/halppc/generic/halinit.c new file mode 100644 index 00000000000..fe78f9bc438 --- /dev/null +++ b/reactos/hal/halppc/generic/halinit.c @@ -0,0 +1,69 @@ +/* $Id: halinit.c 23907 2006-09-04 05:52:23Z arty $ + * + * 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 + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS *****************************************************************/ + +PVOID HalpZeroPageMapping = NULL; +HALP_HOOKS HalpHooks; + +/* FUNCTIONS ***************************************************************/ + +NTSTATUS +STDCALL +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + return STATUS_SUCCESS; +} + +BOOLEAN STDCALL +HalInitSystem (ULONG BootPhase, + PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + if (BootPhase == 0) + { + RtlZeroMemory(&HalpHooks, sizeof(HALP_HOOKS)); + HalpInitPhase0((PROS_LOADER_PARAMETER_BLOCK)LoaderBlock); + } + else if (BootPhase == 1) + { + /* Initialize the clock interrupt */ + //HalpInitPhase1(); + + /* Initialize display and make the screen black */ + HalInitializeDisplay ((PROS_LOADER_PARAMETER_BLOCK)LoaderBlock); + HalpInitBusHandlers(); + HalpInitDma(); + + /* Enumerate the devices on the motherboard */ + HalpStartEnumerator(); + } + else if (BootPhase == 2) + { + PHYSICAL_ADDRESS Null = {{0}}; + + /* Go to blue screen */ + HalClearDisplay (0x17); /* grey on blue */ + + HalpZeroPageMapping = MmMapIoSpace(Null, PAGE_SIZE, MmNonCached); + } + + return TRUE; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/ipi.c b/reactos/hal/halppc/generic/ipi.c new file mode 100644 index 00000000000..739de8d716c --- /dev/null +++ b/reactos/hal/halppc/generic/ipi.c @@ -0,0 +1,24 @@ +/* $Id: ipi.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/ipi.c + * PURPOSE: Miscellaneous hardware functions + * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS ****************************************************************/ + +VOID STDCALL +HalRequestIpi(ULONG ProcessorNo) +{ + DPRINT("HalRequestIpi(ProcessorNo %lu)\n", ProcessorNo); +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/irq.S b/reactos/hal/halppc/generic/irq.S new file mode 100644 index 00000000000..585bb4c83b8 --- /dev/null +++ b/reactos/hal/halppc/generic/irq.S @@ -0,0 +1,631 @@ +/* + * FILE: hal/halx86/generic/irql.S + * COPYRIGHT: See COPYING in the top level directory + * PURPOSE: Software, System and Hardware IRQ Management + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ******************************************************************/ + +#include +#include +.intel_syntax noprefix + +/* GLOBALS *******************************************************************/ + +PICInitTable: + + /* Master PIC */ + .short 0x20 /* Port */ + .byte 0x11 /* Edge,, cascade, CAI 8, ICW4 */ + .byte PRIMARY_VECTOR_BASE /* Base */ + .byte 4 /* IRQ 4 connected to slave */ + .byte 1 /* Non buffered, not nested, 8086 */ + + /* Slave PIC */ + .short 0xA0 /* Port */ + .byte 0x11 /* Edge, cascade, CAI 8, ICW4 */ + .byte PRIMARY_VECTOR_BASE + 8 /* Base */ + .byte 2 /* Slave ID: Slave 2 */ + .byte 1 /* Non buffered, not nested, 8086 */ + + /* End of initialization table */ + .short 0 + +KiI8259MaskTable: + .long 0 /* IRQL 0 */ + .long 0 /* IRQL 1 */ + .long 0 /* IRQL 2 */ + .long 0 /* IRQL 3 */ + .long 0xFF800000 /* IRQL 4 */ + .long 0xFFC00000 /* IRQL 5 */ + .long 0xFFE00000 /* IRQL 6 */ + .long 0xFFF00000 /* IRQL 7 */ + .long 0xFFF80000 /* IRQL 8 */ + .long 0xFFFC0000 /* IRQL 9 */ + .long 0xFFFE0000 /* IRQL 10 */ + .long 0xFFFF0000 /* IRQL 11 */ + .long 0xFFFF8000 /* IRQL 12 */ + .long 0xFFFFC000 /* IRQL 13 */ + .long 0xFFFFE000 /* IRQL 14 */ + .long 0xFFFFF000 /* IRQL 15 */ + .long 0xFFFFF800 /* IRQL 16 */ + .long 0xFFFFFC00 /* IRQL 17 */ + .long 0xFFFFFE00 /* IRQL 18 */ + .long 0xFFFFFE00 /* IRQL 19 */ + .long 0xFFFFFE80 /* IRQL 20 */ + .long 0xFFFFFEC0 /* IRQL 21 */ + .long 0xFFFFFEE0 /* IRQL 22 */ + .long 0xFFFFFEF0 /* IRQL 23 */ + .long 0xFFFFFEF8 /* IRQL 24 */ + .long 0xFFFFFEF8 /* IRQL 25 */ + .long 0xFFFFFEFA /* IRQL 26 */ + .long 0xFFFFFFFA /* IRQL 27 */ + .long 0xFFFFFFFB /* IRQL 28 */ + .long 0xFFFFFFFB /* IRQL 29 */ + .long 0xFFFFFFFB /* IRQL 30 */ + .long 0xFFFFFFFB /* IRQL 31 */ + +HalpSysIntHandler: +.rept 8 + .long GenericIRQ /* IRQ 0-7 */ +.endr + .long IRQ7 /* IRQ 7 */ +.rept 8 + .long GenericIRQ /* IRQ 8-15 */ +.endr + .long IRQ15 /* IRQ 15 */ +.rept 20 + .long GenericIRQ /* IRQ 16-35 */ +.endr + +SoftIntByteTable: + .byte PASSIVE_LEVEL /* IRR 0 */ + .byte PASSIVE_LEVEL /* IRR 1 */ + .byte APC_LEVEL /* IRR 2 */ + .byte APC_LEVEL /* IRR 3 */ + .byte DISPATCH_LEVEL /* IRR 4 */ + .byte DISPATCH_LEVEL /* IRR 5 */ + .byte DISPATCH_LEVEL /* IRR 6 */ + .byte DISPATCH_LEVEL /* IRR 7 */ + +SoftIntHandlerTable: + .long _KiUnexpectedInterrupt /* PASSIVE_LEVEL */ + .long _HalpApcInterrupt /* APC_LEVEL */ + .long _HalpDispatchInterrupt /* DISPATCH_LEVEL */ + +SoftIntHandlerTable2: + .long _KiUnexpectedInterrupt /* PASSIVE_LEVEL */ + .long _HalpApcInterrupt2ndEntry /* APC_LEVEL */ + .long _HalpDispatchInterrupt2ndEntry /* DISPATCH_LEVEL */ + +/* FUNCTIONS *****************************************************************/ + +.globl _HalpInitPICs@0 +.func HalpInitPICs@0 +_HalpInitPICs@0: + + /* Save ESI and disable interrupts */ + push esi + pushf + cli + + /* Read the init table */ + lea esi, PICInitTable + lodsw + +InitLoop: + + /* Put the port in EDX */ + movzx edx, ax + + /* Initialize the PIC, using a delay for each command */ + outsb + jmp $+2 + inc edx + outsb + jmp $+2 + outsb + jmp $+2 + outsb + jmp $+2 + + /* Mask all interrupts */ + mov al, 0xFF + out dx, al + + /* Check if we're done, otherwise initialize next PIC */ + lodsw + cmp ax, 0 + jnz InitLoop + + /* Restore interrupts and return */ + or dword ptr [esp], EFLAGS_INTERRUPT_MASK + popf + pop esi + ret +.endfunc + +.globl @HalRequestSoftwareInterrupt@4 +.func @HalRequestSoftwareInterrupt@4 +_@HalRequestSoftwareInterrupt@4: +@HalRequestSoftwareInterrupt@4: + + /* Get IRR mask */ + mov eax, 1 + shl eax, cl + + /* Disable interrupts */ + pushf + cli + + /* Set IRR and get IRQL */ + or [fs:KPCR_IRR], eax + mov cl, [fs:KPCR_IRQL] + + /* Get software IRR mask */ + mov eax, [fs:KPCR_IRR] + and eax, 3 + + /* Get highest pending software interrupt and check if it's higher */ + xor edx, edx + mov dl, SoftIntByteTable[eax] + cmp dl, cl + jbe AfterCall + + /* Call the pending interrupt */ + call SoftIntHandlerTable[edx*4] + +AfterCall: + + /* Retore interrupts and return */ + popf + ret +.endfunc + +.globl _HalDisableSystemInterrupt@8 +.func HalDisableSystemInterrupt@8 +_HalDisableSystemInterrupt@8: + + /* Convert to vector */ + movzx ecx, byte ptr [esp+4] + sub ecx, PRIMARY_VECTOR_BASE + + /* Disable interrupts and set the new IDR */ + mov edx, 1 + shl edx, cl + cli + or [fs:KPCR_IDR], edx + + /* Get the current mask */ + xor eax, eax + in al, 0xA1 + shl eax, 8 + in al, 0x21 + + /* Mask off the interrupt and write the new mask */ + or eax, edx + out 0x21, al + shr eax, 8 + out 0xA1, al + + /* Return with interrupts enabled */ + in al, 0xA1 + sti + ret 8 +.endfunc + +.globl _HalEnableSystemInterrupt@12 +.func HalEnableSystemInterrupt@12 +_HalEnableSystemInterrupt@12: + + /* Get the vector and validate it */ + movzx ecx, byte ptr [esp+4] + sub ecx, PRIMARY_VECTOR_BASE + jb Invalid + cmp ecx, CLOCK2_LEVEL + jnb Invalid + + /* Get the current PCI Edge/Level control registers */ + mov edx, 0x4D1 + in al, dx + shl ax, 8 + mov eax, 0x4D0 + in al, dx + mov dx, 1 + shl dx, cl + + /* Check if this is a latched interrupt */ + cmp dword ptr [esp+12], 0 + jnz Latched + + /* Use OR for edge interrupt */ + or ax, dx + jmp AfterMask +Latched: + + /* Mask it out for level interrupt */ + not dx + and ax, dx + +AfterMask: + + /* Set the PCI Edge/Level control registers */ + mov edx, 0x4D0 + out dx, al + shr ax, 8 + mov edx, 0x4D1 + out dx, al + + /* Calculate the new IDR */ + mov eax, 1 + shl eax, cl + not eax + cli + and [fs:KPCR_IDR], eax + + /* Get the current IRQL and mask the IRQs in the PIC */ + movzx eax, byte ptr [fs:KPCR_IRQL] + mov eax, KiI8259MaskTable[eax*4] + or eax, [fs:KPCR_IDR] + out 0x21, al + shr eax, 8 + out 0xA1, al + + /* Enable interrupts and return TRUE */ + sti + mov eax, 1 + ret 12 + +Invalid: + + /* Fail, invalid IRQ */ + xor eax, eax + ret 12 +.endfunc + +.globl _HalBeginSystemInterrupt@12 +.func HalBeginSystemInterrupt@12 +_HalBeginSystemInterrupt@12: + + /* Convert to IRQ and call the handler */ + mov edx, [esp+8] + sub edx, PRIMARY_VECTOR_BASE + jmp HalpSysIntHandler[edx*4] + +IRQ15: + /* This is IRQ 15, check if it's spurious */ + mov al, 0xB + out 0xA0, al + in al, 0xA0 + test al, 0x80 + jnz GenericIRQ + + /* Cascaded interrupt... dismiss it and return FALSE */ + mov al, 0x62 + out 0x20, al + mov eax, 0 + ret 12 + +IRQ7: + /* This is IRQ 7, check if it's spurious */ + mov al, 0xB + out 0x20, al + in al, 0x20 + test al, 0x80 + jnz GenericIRQ + + /* It is, return FALSE */ + mov eax, 0 + ret 12 + +GenericIRQ: + /* Return the current IRQL */ + mov eax, [esp+12] + movzx ecx, byte ptr [fs:KPCR_IRQL] + mov [eax], cl + + /* Set the new IRQL */ + movzx eax, byte ptr [esp+4] + mov [fs:KPCR_IRQL], al + + /* Set IRQ mask in the PIC */ + mov eax, KiI8259MaskTable[eax*4] + or eax, [fs:KPCR_IDR] + out 0x21, al + shr eax, 8 + out 0xA1, al + + /* Check to which PIC the EOI was sent */ + mov eax, edx + cmp eax, 8 + jnb Pic1 + + /* Write mask to master PIC */ + or al, 0x60 + out 0x20, al + jmp DoneBegin + +Pic1: + /* Write mask to slave PIC */ + mov al, 0x20 + out 0xA0, al + mov al, 0x62 + out 0x20, al + +DoneBegin: + /* Enable interrupts and return TRUE */ + in al, 0x21 + sti + mov eax, 1 + ret 12 +.endfunc + +.globl _HalEndSystemInterrupt@8 +.func HalEndSystemInterrupt@8 +_HalEndSystemInterrupt@8: + + /* Get the IRQL and check if it's a software interrupt */ + movzx ecx, byte ptr [esp+4] + cmp byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL + jbe SkipMask2 + + /* Hardware interrupt, mask the appropriate IRQs in the PIC */ + mov eax, KiI8259MaskTable[ecx*4] + or eax, [fs:KPCR_IDR] + out 0x21, al + shr eax, 8 + out 0xA1, al + +SkipMask2: + + /* Set IRQL and check if there are pending software interrupts */ + mov [fs:KPCR_IRQL], cl + mov eax, [fs:KPCR_IRR] + mov al, SoftIntByteTable[eax] + cmp al, cl + ja DoCall + ret 8 + +DoCall: + + /* There are pending software interrupts, call their handlers */ + add esp, 12 + jmp SoftIntHandlerTable2[eax*4] +.endfunc + +.globl @KfLowerIrql@4 +.func @KfLowerIrql@4 +_@KfLowerIrql@4: +@KfLowerIrql@4: + + /* Save flags since we'll disable interrupts */ + pushf + + /* Disable interrupts and check if IRQL is below DISPATCH_LEVEL */ + movzx ecx, cl + cmp byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL + cli + jbe SkipMask + + /* Clear interrupt masks since there's a pending hardware interrupt */ + mov eax, KiI8259MaskTable[ecx*4] + or eax, [fs:KPCR_IDR] + out 0x21, al + shr eax, 8 + out 0xA1, al + +SkipMask: + + /* Set the new IRQL and check if there's a pending software interrupt */ + mov [fs:KPCR_IRQL], cl + mov eax, [fs:KPCR_IRR] + mov al, SoftIntByteTable[eax] + cmp al, cl + jbe DoCall3 + + /* There is, call it */ + call SoftIntHandlerTable[eax*4] + +DoCall3: + + /* Restore interrupts and return */ + popf + ret +.endfunc + +.globl @KfRaiseIrql@4 +.func @KfRaiseIrql@4 +_@KfRaiseIrql@4: +@KfRaiseIrql@4: + + /* Get the IRQL and check if it's Software level only */ + xor eax, eax + mov al, [fs:KPCR_IRQL] + movzx ecx, cl + cmp cl, DISPATCH_LEVEL + jbe SetIrql + + /* Save the current IRQL */ + mov edx, eax + + /* It's a hardware IRQL, so disable interrupts */ + pushf + cli + + /* Set the new IRQL */ + mov [fs:KPCR_IRQL], cl + + /* Mask the interrupts in the PIC */ + mov eax, KiI8259MaskTable[ecx*4] + or eax, [fs:KPCR_IDR] + out 0x21, al + shr eax, 8 + out 0xA1, al + + /* Restore interrupts and return old IRQL */ + popf + mov eax, edx + ret + +SetIrql: + + /* Set the IRQL and return */ + mov [fs:KPCR_IRQL], cl + ret +.endfunc + +.globl _KeGetCurrentIrql@0 +.func KeGetCurrentIrql@0 +_KeGetCurrentIrql@0: + + /* Return the IRQL */ + movzx eax, word ptr [fs:KPCR_IRQL] + ret +.endfunc + +.globl _KeRaiseIrqlToDpcLevel@0 +.func KeRaiseIrqlToDpcLevel@0 +_KeRaiseIrqlToDpcLevel@0: + + /* Get the current IRQL */ + xor eax, eax + mov al, [fs:KPCR_IRQL] + + /* Set DISPATCH_LEVEL */ + mov byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL + ret +.endfunc + +.globl _KeRaiseIrqlToSynchLevel@0 +.func KeRaiseIrqlToSynchLevel@0 +_KeRaiseIrqlToSynchLevel@0: + + /* Disable interrupts */ + pushf + cli + + /* Mask out interrupts */ + mov eax, KiI8259MaskTable[DISPATCH_LEVEL*4] + or eax, [fs:KPCR_IDR] + out 0x21, al + shr eax, 8 + out 0xA1, al + + /* Return the old IRQL, enable interrupts and set to DISPATCH */ + mov al, [fs:KPCR_IRQL] + mov byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL + popf + ret +.endfunc + +.globl _HalpApcInterrupt +.func HalpApcInterrupt +_HalpApcInterrupt: + + /* Create fake interrupt stack */ + pop eax + pushf + push cs + push eax + + /* Enter interrupt */ + INT_PROLOG hapc, DoPushFakeErrorCode +.endfunc + +.globl _HalpApcInterrupt2ndEntry +.func HalpApcInterrupt2ndEntry +_HalpApcInterrupt2ndEntry: + + /* Save current IRQL and set to APC level */ + push [fs:KPCR_IRQL] + mov byte ptr [fs:KPCR_IRQL], APC_LEVEL + and dword ptr [fs:KPCR_IRR], ~(1 << APC_LEVEL) + + /* Enable interrupts and check if we came from User/V86 mode */ + sti + mov eax, [ebp+KTRAP_FRAME_CS] + and eax, MODE_MASK + test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK + jz DeliverApc + + /* Set user mode delivery */ + or eax, UserMode + +DeliverApc: + + /* Deliver the APCs */ + push ebp + push 0 + push eax + call _KiDeliverApc@12 + + /* Disable interrupts and end it */ + cli + call _HalpEndSoftwareInterrupt@4 + jmp _Kei386EoiHelper@0 +.endfunc + +.globl _HalpDispatchInterrupt +.func HalpDispatchInterrupt +_HalpDispatchInterrupt: + + /* Create fake interrupt stack */ + pop eax + pushf + push cs + push eax + + /* Enter interrupt */ + INT_PROLOG hapc, DoPushFakeErrorCode +.endfunc + +.globl _HalpDispatchInterrupt2ndEntry +.func HalpDispatchInterrupt2ndEntry +_HalpDispatchInterrupt2ndEntry: + + /* Save current IRQL and set to DPC level */ + push [fs:KPCR_IRQL] + mov byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL + and dword ptr [fs:KPCR_IRR], ~(1 << DISPATCH_LEVEL) + + /* Enable interrupts and let the kernel handle this */ + sti + call _KiDispatchInterrupt@0 + + /* Disable interrupts and end it */ + cli + call _HalpEndSoftwareInterrupt@4 + jmp _Kei386EoiHelper@0 +.endfunc + +.globl _HalpEndSoftwareInterrupt@4 +.func HalpEndSoftwareInterrupt@4 +_HalpEndSoftwareInterrupt@4: + + /* Get the IRQL and check if we're in the software region */ + movzx ecx, byte ptr [esp+4] + cmp byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL + jbe SoftwareInt + + /* Set the right mask in the PIC for the hardware IRQ */ + mov eax, KiI8259MaskTable[ecx*4] + or eax, [fs:KPCR_IDR] + out 0x21, al + shr eax, 8 + out 0xA1, al + +SoftwareInt: + /* Check if there are pending software interrupts */ + mov [fs:KPCR_IRQL], cl + mov eax, [fs:KPCR_IRR] + mov al, SoftIntByteTable[eax] + cmp al, cl + ja DoCall2 + ret 4 + +DoCall2: + /* There are pending softwate interrupts, call their handlers */ + add esp, 8 + jmp SoftIntHandlerTable2[eax*4] +.endfunc diff --git a/reactos/hal/halppc/generic/irql.c b/reactos/hal/halppc/generic/irql.c new file mode 100644 index 00000000000..fd55e42c1f7 --- /dev/null +++ b/reactos/hal/halppc/generic/irql.c @@ -0,0 +1,425 @@ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/irql.c + * PURPOSE: Implements IRQLs + * PROGRAMMER: David Welch (welch@cwcom.net) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ******************************************************************/ + +/* + * FIXME: Use EISA_CONTROL STRUCTURE INSTEAD OF HARD-CODED OFFSETS +*/ + +typedef union +{ + USHORT both; + struct + { + BYTE master; + BYTE slave; + }; +} +PIC_MASK; + +/* + * PURPOSE: - Mask for HalEnableSystemInterrupt and HalDisableSystemInterrupt + * - At startup enable timer and cascade + */ +#if defined(__GNUC__) +static PIC_MASK pic_mask = {.both = 0xFFFA}; +#else +static PIC_MASK pic_mask = { 0xFFFA }; +#endif + + +/* + * PURPOSE: Mask for disabling of acknowledged interrupts + */ +#if defined(__GNUC__) +static PIC_MASK pic_mask_intr = {.both = 0x0000}; +#else +static PIC_MASK pic_mask_intr = { 0 }; +#endif + +static ULONG HalpPendingInterruptCount[NR_IRQS]; + +#define DIRQL_TO_IRQ(x) (PROFILE_LEVEL - x) +#define IRQ_TO_DIRQL(x) (PROFILE_LEVEL - x) + +VOID STDCALL +KiInterruptDispatch2 (ULONG Irq, KIRQL old_level); + +/* FUNCTIONS ****************************************************************/ + +#undef KeGetCurrentIrql +KIRQL STDCALL KeGetCurrentIrql (VOID) +/* + * PURPOSE: Returns the current irq level + * RETURNS: The current irq level + */ +{ + return(KeGetPcr()->Irql); +} + +VOID NTAPI HalpInitPICs(VOID) +{ + memset(HalpPendingInterruptCount, 0, sizeof(HalpPendingInterruptCount)); + + /* Initialization sequence */ + WRITE_PORT_UCHAR((PUCHAR)0x20, 0x11); + WRITE_PORT_UCHAR((PUCHAR)0xa0, 0x11); + /* Start of hardware irqs (0x24) */ + WRITE_PORT_UCHAR((PUCHAR)0x21, IRQ_BASE); + WRITE_PORT_UCHAR((PUCHAR)0xa1, IRQ_BASE + 8); + /* 8259-1 is master */ + WRITE_PORT_UCHAR((PUCHAR)0x21, 0x4); + /* 8259-2 is slave */ + WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x2); + /* 8086 mode */ + WRITE_PORT_UCHAR((PUCHAR)0x21, 0x1); + WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x1); + /* Enable interrupts */ + WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master); + WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave); + + /* We can now enable interrupts */ + Ki386EnableInterrupts(); +} + +VOID HalpEndSystemInterrupt(KIRQL Irql) +/* + * FUNCTION: Enable all irqs with higher priority. + */ +{ + ULONG flags; + const USHORT mask[] = + { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, + 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0, + 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + }; + + /* Interrupts should be disable while enabling irqs of both pics */ + Ki386SaveFlags(flags); + Ki386DisableInterrupts(); + + pic_mask_intr.both &= mask[Irql]; + WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master)); + WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave)); + + /* restore flags */ + Ki386RestoreFlags(flags); +} + +VOID STATIC +HalpExecuteIrqs(KIRQL NewIrql) +{ + ULONG IrqLimit, i; + + IrqLimit = min(PROFILE_LEVEL - NewIrql, NR_IRQS); + + /* + * For each irq if there have been any deferred interrupts then now + * dispatch them. + */ + for (i = 0; i < IrqLimit; i++) + { + if (HalpPendingInterruptCount[i] > 0) + { + KeGetPcr()->Irql = (KIRQL)IRQ_TO_DIRQL(i); + + while (HalpPendingInterruptCount[i] > 0) + { + /* + * For each deferred interrupt execute all the handlers at DIRQL. + */ + HalpPendingInterruptCount[i]--; + KiInterruptDispatch2(i + IRQ_BASE, NewIrql); + } + KeGetPcr()->Irql--; + HalpEndSystemInterrupt(KeGetPcr()->Irql); + } + } + +} + +VOID STATIC +HalpLowerIrql(KIRQL NewIrql) +{ + if (NewIrql >= PROFILE_LEVEL) + { + KeGetPcr()->Irql = NewIrql; + return; + } + HalpExecuteIrqs(NewIrql); + if (NewIrql >= DISPATCH_LEVEL) + { + KeGetPcr()->Irql = NewIrql; + return; + } + KeGetPcr()->Irql = DISPATCH_LEVEL; + if (((PKIPCR)KeGetPcr())->HalReserved[HAL_DPC_REQUEST]) + { + ((PKIPCR)KeGetPcr())->HalReserved[HAL_DPC_REQUEST] = FALSE; + KiDispatchInterrupt(); + } + KeGetPcr()->Irql = APC_LEVEL; + if (NewIrql == APC_LEVEL) + { + return; + } + if (KeGetCurrentThread() != NULL && + KeGetCurrentThread()->ApcState.KernelApcPending) + { + KiDeliverApc(KernelMode, NULL, NULL); + } + KeGetPcr()->Irql = PASSIVE_LEVEL; +} + +/********************************************************************** + * NAME EXPORTED + * KfLowerIrql + * + * DESCRIPTION + * Restores the irq level on the current processor + * + * ARGUMENTS + * NewIrql = Irql to lower to + * + * RETURN VALUE + * None + * + * NOTES + * Uses fastcall convention + */ +VOID FASTCALL +KfLowerIrql (KIRQL NewIrql) +{ + DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql); + + if (NewIrql > KeGetPcr()->Irql) + { + DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n", + __FILE__, __LINE__, NewIrql, KeGetPcr()->Irql); + KEBUGCHECK(0); + for(;;); + } + + HalpLowerIrql(NewIrql); +} + +/********************************************************************** + * NAME EXPORTED + * KfRaiseIrql + * + * DESCRIPTION + * Raises the hardware priority (irql) + * + * ARGUMENTS + * NewIrql = Irql to raise to + * + * RETURN VALUE + * previous irq level + * + * NOTES + * Uses fastcall convention + */ + +KIRQL FASTCALL +KfRaiseIrql (KIRQL NewIrql) +{ + KIRQL OldIrql; + + DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql); + + if (NewIrql < KeGetPcr()->Irql) + { + DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n", + __FILE__,__LINE__,KeGetPcr()->Irql,NewIrql); + KEBUGCHECK (0); + for(;;); + } + + OldIrql = KeGetPcr()->Irql; + KeGetPcr()->Irql = NewIrql; + return OldIrql; +} + +/********************************************************************** + * NAME EXPORTED + * KeRaiseIrqlToDpcLevel + * + * DESCRIPTION + * Raises the hardware priority (irql) to DISPATCH level + * + * ARGUMENTS + * None + * + * RETURN VALUE + * Previous irq level + * + * NOTES + * Calls KfRaiseIrql + */ + +KIRQL STDCALL +KeRaiseIrqlToDpcLevel (VOID) +{ + return KfRaiseIrql (DISPATCH_LEVEL); +} + + +/********************************************************************** + * NAME EXPORTED + * KeRaiseIrqlToSynchLevel + * + * DESCRIPTION + * Raises the hardware priority (irql) to CLOCK2 level + * + * ARGUMENTS + * None + * + * RETURN VALUE + * Previous irq level + * + * NOTES + * Calls KfRaiseIrql + */ + +KIRQL STDCALL +KeRaiseIrqlToSynchLevel (VOID) +{ + return KfRaiseIrql (CLOCK2_LEVEL); +} + + +BOOLEAN STDCALL +HalBeginSystemInterrupt (KIRQL Irql, + ULONG Vector, + PKIRQL OldIrql) +{ + ULONG irq; + if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS) + { + return(FALSE); + } + irq = Vector - IRQ_BASE; + pic_mask_intr.both |= ((1 << irq) & 0xfffe); // do not disable the timer interrupt + + if (irq < 8) + { + WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master)); + WRITE_PORT_UCHAR((PUCHAR)0x20, 0x20); + } + else + { + WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave)); + /* Send EOI to the PICs */ + WRITE_PORT_UCHAR((PUCHAR)0x20,0x20); + WRITE_PORT_UCHAR((PUCHAR)0xa0,0x20); + } + + if (KeGetPcr()->Irql >= Irql) + { + HalpPendingInterruptCount[irq]++; + return(FALSE); + } + *OldIrql = KeGetPcr()->Irql; + KeGetPcr()->Irql = Irql; + + return(TRUE); +} + + +VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2) +/* + * FUNCTION: Finish a system interrupt and restore the specified irq level. + */ +{ + HalpLowerIrql(Irql); + HalpEndSystemInterrupt(Irql); +} + +BOOLEAN +STDCALL +HalDisableSystemInterrupt( + ULONG Vector, + KIRQL Irql) +{ + ULONG irq; + + if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS) + return FALSE; + + irq = Vector - IRQ_BASE; + pic_mask.both |= (1 << irq); + if (irq < 8) + { + WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.slave)); + } + else + { + WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave)); + } + + return TRUE; +} + + +BOOLEAN +STDCALL +HalEnableSystemInterrupt( + ULONG Vector, + KIRQL Irql, + KINTERRUPT_MODE InterruptMode) +{ + ULONG irq; + + if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS) + return FALSE; + + irq = Vector - IRQ_BASE; + pic_mask.both &= ~(1 << irq); + if (irq < 8) + { + WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master)); + } + else + { + WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave)); + } + + return TRUE; +} + + +VOID FASTCALL +HalRequestSoftwareInterrupt( + IN KIRQL Request) +{ + switch (Request) + { + case APC_LEVEL: + ((PKIPCR)KeGetPcr())->HalReserved[HAL_APC_REQUEST] = TRUE; + break; + + case DISPATCH_LEVEL: + ((PKIPCR)KeGetPcr())->HalReserved[HAL_DPC_REQUEST] = TRUE; + break; + + default: + KEBUGCHECK(0); + } +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/isa.c b/reactos/hal/halppc/generic/isa.c new file mode 100644 index 00000000000..665bb1edd45 --- /dev/null +++ b/reactos/hal/halppc/generic/isa.c @@ -0,0 +1,75 @@ +/* $Id: isa.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/isa.c + * PURPOSE: Interfaces to the ISA bus + * PROGRAMMER: David Welch (welch@mcmail.com) + * UPDATE HISTORY: + * 05/06/98: Created + */ + +/* INCLUDES ***************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN HalIsaProbe(VOID) +/* + * FUNCTION: Probes for an ISA bus + * RETURNS: True if detected + * NOTE: Since ISA is the default we are called last and always return + * true + */ +{ + DbgPrint("Assuming ISA bus\n"); + + /* + * Probe for plug and play support + */ + return(TRUE); +} + + +BOOLEAN STDCALL +HalpTranslateIsaBusAddress(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PHYSICAL_ADDRESS BusAddress, + PULONG AddressSpace, + PPHYSICAL_ADDRESS TranslatedAddress) +{ + BOOLEAN Result; + + Result = HalTranslateBusAddress(PCIBus, + BusNumber, + BusAddress, + AddressSpace, + TranslatedAddress); + if (Result != FALSE) + return Result; + + Result = HalTranslateBusAddress(Internal, + BusNumber, + BusAddress, + AddressSpace, + TranslatedAddress); + return Result; +} + +ULONG STDCALL +HalpGetIsaInterruptVector(PVOID BusHandler, + ULONG BusNumber, + ULONG BusInterruptLevel, + ULONG BusInterruptVector, + PKIRQL Irql, + PKAFFINITY Affinity) +{ + ULONG Vector = IRQ2VECTOR(BusInterruptVector); + *Irql = VECTOR2IRQL(Vector); + *Affinity = 0xFFFFFFFF; + return Vector; +} +/* EOF */ diff --git a/reactos/hal/halppc/generic/kdbg.c b/reactos/hal/halppc/generic/kdbg.c new file mode 100644 index 00000000000..fdc0e223ae4 --- /dev/null +++ b/reactos/hal/halppc/generic/kdbg.c @@ -0,0 +1,547 @@ +/* $Id: kdbg.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/kdbg.c + * PURPOSE: Serial i/o functions for the kernel debugger. + * PROGRAMMER: Emanuele Aliberti + * Eric Kohl + * UPDATE HISTORY: + * Created 05/09/99 + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + +#define DEFAULT_BAUD_RATE 19200 + + +/* MACROS *******************************************************************/ + +#define SER_RBR(x) ((x)+0) +#define SER_THR(x) ((x)+0) +#define SER_DLL(x) ((x)+0) +#define SER_IER(x) ((x)+1) +#define SR_IER_ERDA 0x01 +#define SR_IER_ETHRE 0x02 +#define SR_IER_ERLSI 0x04 +#define SR_IER_EMS 0x08 +#define SR_IER_ALL 0x0F +#define SER_DLM(x) ((x)+1) +#define SER_IIR(x) ((x)+2) +#define SER_FCR(x) ((x)+2) +#define SR_FCR_ENABLE_FIFO 0x01 +#define SR_FCR_CLEAR_RCVR 0x02 +#define SR_FCR_CLEAR_XMIT 0x04 +#define SER_LCR(x) ((x)+3) +#define SR_LCR_CS5 0x00 +#define SR_LCR_CS6 0x01 +#define SR_LCR_CS7 0x02 +#define SR_LCR_CS8 0x03 +#define SR_LCR_ST1 0x00 +#define SR_LCR_ST2 0x04 +#define SR_LCR_PNO 0x00 +#define SR_LCR_POD 0x08 +#define SR_LCR_PEV 0x18 +#define SR_LCR_PMK 0x28 +#define SR_LCR_PSP 0x38 +#define SR_LCR_BRK 0x40 +#define SR_LCR_DLAB 0x80 +#define SER_MCR(x) ((x)+4) +#define SR_MCR_DTR 0x01 +#define SR_MCR_RTS 0x02 +#define SR_MCR_OUT1 0x04 +#define SR_MCR_OUT2 0x08 +#define SR_MCR_LOOP 0x10 +#define SER_LSR(x) ((x)+5) +#define SR_LSR_DR 0x01 +#define SR_LSR_TBE 0x20 +#define SER_MSR(x) ((x)+6) +#define SR_MSR_CTS 0x10 +#define SR_MSR_DSR 0x20 +#define SER_SCR(x) ((x)+7) + + +/* GLOBAL VARIABLES *********************************************************/ + +ULONG KdComPortInUse = 0; + + +/* STATIC VARIABLES *********************************************************/ + +static ULONG ComPort = 0; +static ULONG BaudRate = 0; +static PUCHAR PortBase = (PUCHAR)0; + +/* The com port must only be initialized once! */ +static BOOLEAN PortInitialized = FALSE; + + +/* STATIC FUNCTIONS *********************************************************/ + +static BOOLEAN +KdpDoesComPortExist (PUCHAR BaseAddress) +{ + BOOLEAN found; + UCHAR mcr; + UCHAR msr; + + found = FALSE; + + /* save Modem Control Register (MCR) */ + mcr = READ_PORT_UCHAR (SER_MCR(BaseAddress)); + + /* enable loop mode (set Bit 4 of the MCR) */ + WRITE_PORT_UCHAR (SER_MCR(BaseAddress), 0x10); + + /* clear all modem output bits */ + WRITE_PORT_UCHAR (SER_MCR(BaseAddress), 0x10); + + /* read the Modem Status Register */ + msr = READ_PORT_UCHAR (SER_MSR(BaseAddress)); + + /* + * the upper nibble of the MSR (modem output bits) must be + * equal to the lower nibble of the MCR (modem input bits) + */ + if ((msr & 0xF0) == 0x00) + { + /* set all modem output bits */ + WRITE_PORT_UCHAR (SER_MCR(BaseAddress), 0x1F); + + /* read the Modem Status Register */ + msr = READ_PORT_UCHAR (SER_MSR(BaseAddress)); + + /* + * the upper nibble of the MSR (modem output bits) must be + * equal to the lower nibble of the MCR (modem input bits) + */ + if ((msr & 0xF0) == 0xF0) + { + /* + * setup a resonable state for the port: + * enable fifo and clear recieve/transmit buffers + */ + WRITE_PORT_UCHAR (SER_FCR(BaseAddress), + (SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT)); + WRITE_PORT_UCHAR (SER_FCR(BaseAddress), 0); + READ_PORT_UCHAR (SER_RBR(BaseAddress)); + WRITE_PORT_UCHAR (SER_IER(BaseAddress), 0); + found = TRUE; + } + } + + /* restore MCR */ + WRITE_PORT_UCHAR (SER_MCR(BaseAddress), mcr); + + return (found); +} + + +/* FUNCTIONS ****************************************************************/ + +/* HAL.KdPortInitialize */ +BOOLEAN +STDCALL +KdPortInitialize ( + PKD_PORT_INFORMATION PortInformation, + ULONG Unknown1, + ULONG Unknown2 + ) +{ + ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8}; + char buffer[80]; + ULONG divisor; + UCHAR lcr; + + if (PortInitialized == FALSE) + { + if (PortInformation->BaudRate != 0) + { + BaudRate = PortInformation->BaudRate; + } + else + { + BaudRate = DEFAULT_BAUD_RATE; + } + + if (PortInformation->ComPort == 0) + { + if (KdpDoesComPortExist ((PUCHAR)BaseArray[2])) + { + PortBase = (PUCHAR)BaseArray[2]; + ComPort = 2; + PortInformation->BaseAddress = (ULONG)PortBase; + PortInformation->ComPort = ComPort; +#ifndef NDEBUG + sprintf (buffer, + "\nSerial port COM%ld found at 0x%lx\n", + ComPort, + (ULONG)PortBase); + HalDisplayString (buffer); +#endif /* NDEBUG */ + } + else if (KdpDoesComPortExist ((PUCHAR)BaseArray[1])) + { + PortBase = (PUCHAR)BaseArray[1]; + ComPort = 1; + PortInformation->BaseAddress = (ULONG)PortBase; + PortInformation->ComPort = ComPort; +#ifndef NDEBUG + sprintf (buffer, + "\nSerial port COM%ld found at 0x%lx\n", + ComPort, + (ULONG)PortBase); + HalDisplayString (buffer); +#endif /* NDEBUG */ + } + else + { + sprintf (buffer, + "\nKernel Debugger: No COM port found!!!\n\n"); + HalDisplayString (buffer); + return FALSE; + } + } + else + { + if (KdpDoesComPortExist ((PUCHAR)BaseArray[PortInformation->ComPort])) + { + PortBase = (PUCHAR)BaseArray[PortInformation->ComPort]; + ComPort = PortInformation->ComPort; + PortInformation->BaseAddress = (ULONG)PortBase; +#ifndef NDEBUG + sprintf (buffer, + "\nSerial port COM%ld found at 0x%lx\n", + ComPort, + (ULONG)PortBase); + HalDisplayString (buffer); +#endif /* NDEBUG */ + } + else + { + sprintf (buffer, + "\nKernel Debugger: No serial port found!!!\n\n"); + HalDisplayString (buffer); + return FALSE; + } + } + + PortInitialized = TRUE; + } + + /* + * set baud rate and data format (8N1) + */ + + /* turn on DTR and RTS */ + WRITE_PORT_UCHAR (SER_MCR(PortBase), SR_MCR_DTR | SR_MCR_RTS); + + /* set DLAB */ + lcr = READ_PORT_UCHAR (SER_LCR(PortBase)) | SR_LCR_DLAB; + WRITE_PORT_UCHAR (SER_LCR(PortBase), lcr); + + /* set baud rate */ + divisor = 115200 / BaudRate; + WRITE_PORT_UCHAR (SER_DLL(PortBase), (UCHAR)(divisor & 0xff)); + WRITE_PORT_UCHAR (SER_DLM(PortBase), (UCHAR)((divisor >> 8) & 0xff)); + + /* reset DLAB and set 8N1 format */ + WRITE_PORT_UCHAR (SER_LCR(PortBase), + SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO); + + /* read junk out of the RBR */ + lcr = READ_PORT_UCHAR (SER_RBR(PortBase)); + + /* + * set global info + */ + KdComPortInUse = (ULONG)PortBase; + + /* + * print message to blue screen + */ + sprintf (buffer, + "\nKernel Debugger: COM%ld (Port 0x%lx) BaudRate %ld\n\n", + ComPort, + (ULONG)PortBase, + BaudRate); + + HalDisplayString (buffer); + + return TRUE; +} + + +/* HAL.KdPortInitializeEx */ +BOOLEAN +STDCALL +KdPortInitializeEx ( + PKD_PORT_INFORMATION PortInformation, + ULONG Unknown1, + ULONG Unknown2 + ) +{ + ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8}; + PUCHAR ComPortBase; + char buffer[80]; + ULONG divisor; + UCHAR lcr; + + if (PortInformation->BaudRate == 0) + { + PortInformation->BaudRate = DEFAULT_BAUD_RATE; + } + + if (PortInformation->ComPort == 0) + { + return FALSE; + } + else + { + if (KdpDoesComPortExist ((PUCHAR)BaseArray[PortInformation->ComPort])) + { + ComPortBase = (PUCHAR)BaseArray[PortInformation->ComPort]; + PortInformation->BaseAddress = (ULONG)ComPortBase; +#ifndef NDEBUG + sprintf (buffer, + "\nSerial port COM%ld found at 0x%lx\n", + PortInformation->ComPort, + (ULONG)ComPortBase]; + HalDisplayString (buffer); +#endif /* NDEBUG */ + } + else + { + sprintf (buffer, + "\nKernel Debugger: Serial port not found!!!\n\n"); + HalDisplayString (buffer); + return FALSE; + } + } + + /* + * set baud rate and data format (8N1) + */ + + /* turn on DTR and RTS */ + WRITE_PORT_UCHAR (SER_MCR(ComPortBase), SR_MCR_DTR | SR_MCR_RTS); + + /* set DLAB */ + lcr = READ_PORT_UCHAR (SER_LCR(ComPortBase)) | SR_LCR_DLAB; + WRITE_PORT_UCHAR (SER_LCR(ComPortBase), lcr); + + /* set baud rate */ + divisor = 115200 / PortInformation->BaudRate; + WRITE_PORT_UCHAR (SER_DLL(ComPortBase), (UCHAR)(divisor & 0xff)); + WRITE_PORT_UCHAR (SER_DLM(ComPortBase), (UCHAR)((divisor >> 8) & 0xff)); + + /* reset DLAB and set 8N1 format */ + WRITE_PORT_UCHAR (SER_LCR(ComPortBase), + SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO); + + /* read junk out of the RBR */ + lcr = READ_PORT_UCHAR (SER_RBR(ComPortBase)); + +#ifndef NDEBUG + + /* + * print message to blue screen + */ + sprintf (buffer, + "\nKernel Debugger: COM%ld (Port 0x%lx) BaudRate %ld\n\n", + PortInformation->ComPort, + (ULONG)ComPortBase, + PortInformation->BaudRate); + + HalDisplayString (buffer); + +#endif /* NDEBUG */ + + return TRUE; +} + + +/* HAL.KdPortGetByte */ +BOOLEAN +STDCALL +KdPortGetByte ( + PUCHAR ByteRecieved + ) +{ + if (PortInitialized == FALSE) + return FALSE; + + if ((READ_PORT_UCHAR (SER_LSR(PortBase)) & SR_LSR_DR)) + { + *ByteRecieved = READ_PORT_UCHAR (SER_RBR(PortBase)); + return TRUE; + } + + return FALSE; +} + + +/* HAL.KdPortGetByteEx */ +BOOLEAN +STDCALL +KdPortGetByteEx ( + PKD_PORT_INFORMATION PortInformation, + PUCHAR ByteRecieved + ) +{ + PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress; + + if ((READ_PORT_UCHAR (SER_LSR(ComPortBase)) & SR_LSR_DR)) + { + *ByteRecieved = READ_PORT_UCHAR (SER_RBR(ComPortBase)); + return TRUE; + } + + return FALSE; +} + + +/* HAL.KdPortPollByte */ +BOOLEAN +STDCALL +KdPortPollByte ( + PUCHAR ByteRecieved + ) +{ + if (PortInitialized == FALSE) + return FALSE; + + while ((READ_PORT_UCHAR (SER_LSR(PortBase)) & SR_LSR_DR) == 0) + ; + + *ByteRecieved = READ_PORT_UCHAR (SER_RBR(PortBase)); + + return TRUE; +} + + +/* HAL.KdPortPollByteEx */ +BOOLEAN +STDCALL +KdPortPollByteEx ( + PKD_PORT_INFORMATION PortInformation, + PUCHAR ByteRecieved + ) +{ + PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress; + + while ((READ_PORT_UCHAR (SER_LSR(ComPortBase)) & SR_LSR_DR) == 0) + ; + + *ByteRecieved = READ_PORT_UCHAR (SER_RBR(ComPortBase)); + + return TRUE; +} + + + + +/* HAL.KdPortPutByte */ +VOID +STDCALL +KdPortPutByte ( + UCHAR ByteToSend + ) +{ + if (PortInitialized == FALSE) + return; + + while ((READ_PORT_UCHAR (SER_LSR(PortBase)) & SR_LSR_TBE) == 0) + ; + + WRITE_PORT_UCHAR (SER_THR(PortBase), ByteToSend); +} + +/* HAL.KdPortPutByteEx */ +VOID +STDCALL +KdPortPutByteEx ( + PKD_PORT_INFORMATION PortInformation, + UCHAR ByteToSend + ) +{ + PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress; + + while ((READ_PORT_UCHAR (SER_LSR(ComPortBase)) & SR_LSR_TBE) == 0) + ; + + WRITE_PORT_UCHAR (SER_THR(ComPortBase), ByteToSend); +} + + +/* HAL.KdPortRestore */ +VOID +STDCALL +KdPortRestore ( + VOID + ) +{ +} + + +/* HAL.KdPortSave */ +VOID +STDCALL +KdPortSave ( + VOID + ) +{ +} + + +/* HAL.KdPortDisableInterrupts */ +BOOLEAN +STDCALL +KdPortDisableInterrupts() +{ + UCHAR ch; + + if (PortInitialized == FALSE) + return FALSE; + + ch = READ_PORT_UCHAR (SER_MCR (PortBase)); + ch &= (~(SR_MCR_OUT1 | SR_MCR_OUT2)); + WRITE_PORT_UCHAR (SER_MCR (PortBase), ch); + + ch = READ_PORT_UCHAR (SER_IER (PortBase)); + ch &= (~SR_IER_ALL); + WRITE_PORT_UCHAR (SER_IER (PortBase), ch); + + return TRUE; +} + + +/* HAL.KdPortEnableInterrupts */ +BOOLEAN +STDCALL +KdPortEnableInterrupts() +{ + UCHAR ch; + + if (PortInitialized == FALSE) + return FALSE; + + ch = READ_PORT_UCHAR (SER_IER (PortBase)); + ch &= (~SR_IER_ALL); + ch |= SR_IER_ERDA; + WRITE_PORT_UCHAR (SER_IER (PortBase), ch); + + ch = READ_PORT_UCHAR (SER_MCR (PortBase)); + ch &= (~SR_MCR_LOOP); + ch |= (SR_MCR_OUT1 | SR_MCR_OUT2); + WRITE_PORT_UCHAR (SER_MCR (PortBase), ch); + + return TRUE; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/mca.c b/reactos/hal/halppc/generic/mca.c new file mode 100644 index 00000000000..8343c8a8f70 --- /dev/null +++ b/reactos/hal/halppc/generic/mca.c @@ -0,0 +1,79 @@ +/* + * 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: mca.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/mca.c + * PURPOSE: Interfaces to the MicroChannel bus + * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + */ + +/* + * TODO: + * What Adapter ID is read from an empty slot? + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS ****************************************************************/ + +ULONG STDCALL +HalpGetMicroChannelData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + PCM_MCA_POS_DATA PosData = (PCM_MCA_POS_DATA)Buffer; + + DPRINT("HalpGetMicroChannelData() called.\n"); + DPRINT(" BusNumber %lu\n", BusNumber); + DPRINT(" SlotNumber %lu\n", SlotNumber); + DPRINT(" Offset 0x%lx\n", Offset); + DPRINT(" Length 0x%lx\n", Length); + + if ((BusNumber != 0) || + (SlotNumber == 0) || (SlotNumber > 8) || + (Length < sizeof(CM_MCA_POS_DATA))) + return(0); + + /* Enter Setup-Mode for given slot */ + WRITE_PORT_UCHAR((PUCHAR)0x96, (UCHAR)(((UCHAR)(SlotNumber - 1) & 0x07) | 0x08)); + + /* Read POS data */ + PosData->AdapterId = (READ_PORT_UCHAR((PUCHAR)0x101) << 8) + + READ_PORT_UCHAR((PUCHAR)0x100); + PosData->PosData1 = READ_PORT_UCHAR((PUCHAR)0x102); + PosData->PosData2 = READ_PORT_UCHAR((PUCHAR)0x103); + PosData->PosData3 = READ_PORT_UCHAR((PUCHAR)0x104); + PosData->PosData4 = READ_PORT_UCHAR((PUCHAR)0x105); + + /* Leave Setup-Mode for given slot */ + WRITE_PORT_UCHAR((PUCHAR)0x96, (UCHAR)((UCHAR)(SlotNumber - 1) & 0x07)); + + return(sizeof(CM_MCA_POS_DATA)); +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/misc.c b/reactos/hal/halppc/generic/misc.c new file mode 100644 index 00000000000..14410083d2f --- /dev/null +++ b/reactos/hal/halppc/generic/misc.c @@ -0,0 +1,72 @@ +/* $Id: misc.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/misc.c + * PURPOSE: Miscellaneous hardware functions + * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + +/* FUNCTIONS ****************************************************************/ + +PVOID STDCALL +HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject, + IN OUT PULONG NumberOfMapRegisters) +{ + UNIMPLEMENTED; + return NULL; +} + + +VOID STDCALL +HalHandleNMI(PVOID NmiInfo) +{ + UCHAR ucStatus; + + ucStatus = READ_PORT_UCHAR((PUCHAR) 0x61); + + HalDisplayString ("\n*** Hardware Malfunction\n\n"); + HalDisplayString ("Call your hardware vendor for support\n\n"); + + if (ucStatus & 0x80) + HalDisplayString ("NMI: Parity Check / Memory Parity Error\n"); + + if (ucStatus & 0x40) + HalDisplayString ("NMI: Channel Check / IOCHK\n"); + + HalDisplayString ("\n*** The system has halted ***\n"); + KeEnterKernelDebugger (); +} + + +VOID STDCALL +HalProcessorIdle(VOID) +{ + // XXX Learn to use PSL_POW for this. +} + +ULONG FASTCALL +HalSystemVectorDispatchEntry ( + ULONG Unknown1, + ULONG Unknown2, + ULONG Unknown3 + ) +{ + return 0; +} + + +VOID STDCALL +KeFlushWriteBuffer(VOID) +{ + return; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/pci.c b/reactos/hal/halppc/generic/pci.c new file mode 100644 index 00000000000..f2fd74888f9 --- /dev/null +++ b/reactos/hal/halppc/generic/pci.c @@ -0,0 +1,812 @@ +/* $Id: pci.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/pci.c + * PURPOSE: Interfaces to the PCI bus + * PROGRAMMER: David Welch (welch@mcmail.com) + * Eric Kohl (ekohl@rz-online.de) + * UPDATE HISTORY: + * 05/06/1998: Created + * 17/08/2000: Added preliminary pci bus scanner + * 13/06/2001: Implemented access to pci configuration space + */ + +/* + * NOTES: Sections copied from the Linux pci support + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + +/* MACROS ******************************************************************/ + +/* FIXME These are also defined in drivers/bus/pci/pcidef.h. + Maybe put PCI definitions in a central include file??? */ + +/* access type 1 macros */ +#define CONFIG_CMD(bus, dev_fn, where) \ + (0x80000000 | (((ULONG)(bus)) << 16) | (((dev_fn) & 0x1F) << 11) | (((dev_fn) & 0xE0) << 3) | ((where) & ~3)) + +/* access type 2 macros */ +#define IOADDR(dev_fn, where) \ + (0xC000 | (((dev_fn) & 0x1F) << 8) | (where)) +#define FUNC(dev_fn) \ + ((((dev_fn) & 0xE0) >> 4) | 0xf0) + +#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ +#define PCI_BASE_ADDRESS_SPACE_IO 0x01 +#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 +#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 +#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ +#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ +#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ +#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ +#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) +#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) +/* bit 1 is reserved if address_space = 1 */ + + +/* GLOBALS ******************************************************************/ + +#define TAG_PCI TAG('P', 'C', 'I', 'H') + +static ULONG BusConfigType = 0; /* undetermined config type */ +static KSPIN_LOCK PciLock; + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +ReadPciConfigUchar(UCHAR Bus, + UCHAR Slot, + UCHAR Offset, + PUCHAR Value) +{ + KIRQL oldIrql; + + switch (BusConfigType) + { + case 1: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset)); + *Value = READ_PORT_UCHAR((PUCHAR)0xCFC + (Offset & 3)); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + + case 2: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot)); + WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus); + *Value = READ_PORT_UCHAR((PUCHAR)(IOADDR(Slot, Offset))); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + + +static NTSTATUS +ReadPciConfigUshort(UCHAR Bus, + UCHAR Slot, + UCHAR Offset, + PUSHORT Value) +{ + KIRQL oldIrql; + + if ((Offset & 1) != 0) + { + return STATUS_INVALID_PARAMETER; + } + + switch (BusConfigType) + { + case 1: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset)); + *Value = READ_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2)); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + + case 2: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot)); + WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus); + *Value = READ_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset))); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + + +static NTSTATUS +ReadPciConfigUlong(UCHAR Bus, + UCHAR Slot, + UCHAR Offset, + PULONG Value) +{ + KIRQL oldIrql; + + if ((Offset & 3) != 0) + { + return STATUS_INVALID_PARAMETER; + } + + switch (BusConfigType) + { + case 1: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset)); + *Value = READ_PORT_ULONG((PULONG)0xCFC); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + + case 2: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot)); + WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus); + *Value = READ_PORT_ULONG((PULONG)(IOADDR(Slot, Offset))); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + + +static NTSTATUS +WritePciConfigUchar(UCHAR Bus, + UCHAR Slot, + UCHAR Offset, + UCHAR Value) +{ + KIRQL oldIrql; + + switch (BusConfigType) + { + case 1: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset)); + WRITE_PORT_UCHAR((PUCHAR)0xCFC + (Offset&3), Value); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + + case 2: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot)); + WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus); + WRITE_PORT_UCHAR((PUCHAR)(IOADDR(Slot,Offset)), Value); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + + +static NTSTATUS +WritePciConfigUshort(UCHAR Bus, + UCHAR Slot, + UCHAR Offset, + USHORT Value) +{ + KIRQL oldIrql; + + if ((Offset & 1) != 0) + { + return STATUS_INVALID_PARAMETER; + } + + switch (BusConfigType) + { + case 1: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset)); + WRITE_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2), Value); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + + case 2: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot)); + WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus); + WRITE_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)), Value); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + + +static NTSTATUS +WritePciConfigUlong(UCHAR Bus, + UCHAR Slot, + UCHAR Offset, + ULONG Value) +{ + KIRQL oldIrql; + + if ((Offset & 3) != 0) + { + return STATUS_INVALID_PARAMETER; + } + + switch (BusConfigType) + { + case 1: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset)); + WRITE_PORT_ULONG((PULONG)0xCFC, Value); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + + case 2: + KeAcquireSpinLock(&PciLock, &oldIrql); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot)); + WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus); + WRITE_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)), Value); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0); + KeReleaseSpinLock(&PciLock, oldIrql); + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} + + +static ULONG STDCALL +HalpGetPciData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + PVOID Ptr = Buffer; + ULONG Address = Offset; + ULONG Len = Length; + ULONG Vendor; + UCHAR HeaderType; + + DPRINT("HalpGetPciData() called.\n"); + DPRINT(" BusNumber %lu\n", BusNumber); + DPRINT(" SlotNumber %lu\n", SlotNumber); + DPRINT(" Offset 0x%lx\n", Offset); + DPRINT(" Length 0x%lx\n", Length); + + if ((Length == 0) || (BusConfigType == 0)) + return 0; + + ReadPciConfigUlong((UCHAR)BusNumber, + (UCHAR)(SlotNumber & 0x1F), + 0x00, + &Vendor); + /* some broken boards return 0 if a slot is empty: */ + if (Vendor == 0xFFFFFFFF || Vendor == 0) + { + if (BusNumber == 0 && Offset == 0 && Length >= 2) + { + *(PUSHORT)Buffer = PCI_INVALID_VENDORID; + return 2; + } + return 0; + } + + /* 0E=PCI_HEADER_TYPE */ + ReadPciConfigUchar((UCHAR)BusNumber, + (UCHAR)(SlotNumber & 0x1F), + 0x0E, + &HeaderType); + if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0)) + { + if (Offset == 0 && Length >= 2) + { + *(PUSHORT)Buffer = PCI_INVALID_VENDORID; + return 2; + } + return 0; + } + ReadPciConfigUlong((UCHAR)BusNumber, + (UCHAR)SlotNumber, + 0x00, + &Vendor); + /* some broken boards return 0 if a slot is empty: */ + if (Vendor == 0xFFFFFFFF || Vendor == 0) + { + if (BusNumber == 0 && Offset == 0 && Length >= 2) + { + *(PUSHORT)Buffer = PCI_INVALID_VENDORID; + return 2; + } + return 0; + } + + if ((Address & 1) && (Len >= 1)) + { + ReadPciConfigUchar((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + Ptr); + Ptr = (char*)Ptr + 1; + Address++; + Len--; + } + + if ((Address & 2) && (Len >= 2)) + { + ReadPciConfigUshort((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + Ptr); + Ptr = (char*)Ptr + 2; + Address += 2; + Len -= 2; + } + + while (Len >= 4) + { + ReadPciConfigUlong((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + Ptr); + Ptr = (char*)Ptr + 4; + Address += 4; + Len -= 4; + } + + if (Len >= 2) + { + ReadPciConfigUshort((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + Ptr); + Ptr = (char*)Ptr + 2; + Address += 2; + Len -= 2; + } + + if (Len >= 1) + { + ReadPciConfigUchar((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + Ptr); + Ptr = (char*)Ptr + 1; + Address++; + Len--; + } + + return Length - Len; +} + + +static ULONG STDCALL +HalpSetPciData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + PVOID Ptr = Buffer; + ULONG Address = Offset; + ULONG Len = Length; + ULONG Vendor; + UCHAR HeaderType; + + DPRINT("HalpSetPciData() called.\n"); + DPRINT(" BusNumber %lu\n", BusNumber); + DPRINT(" SlotNumber %lu\n", SlotNumber); + DPRINT(" Offset 0x%lx\n", Offset); + DPRINT(" Length 0x%lx\n", Length); + + if ((Length == 0) || (BusConfigType == 0)) + return 0; + + ReadPciConfigUlong((UCHAR)BusNumber, + (UCHAR)(SlotNumber & 0x1F), + 0x00, + &Vendor); + /* some broken boards return 0 if a slot is empty: */ + if (Vendor == 0xFFFFFFFF || Vendor == 0) + return 0; + + + /* 0E=PCI_HEADER_TYPE */ + ReadPciConfigUchar((UCHAR)BusNumber, + (UCHAR)(SlotNumber & 0x1F), + 0x0E, + &HeaderType); + if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0)) + return 0; + + ReadPciConfigUlong((UCHAR)BusNumber, + (UCHAR)SlotNumber, + 0x00, + &Vendor); + /* some broken boards return 0 if a slot is empty: */ + if (Vendor == 0xFFFFFFFF || Vendor == 0) + return 0; + + if ((Address & 1) && (Len >= 1)) + { + WritePciConfigUchar((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + *(PUCHAR)Ptr); + Ptr = (char*)Ptr + 1; + Address++; + Len--; + } + + if ((Address & 2) && (Len >= 2)) + { + WritePciConfigUshort((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + *(PUSHORT)Ptr); + Ptr = (char*)Ptr + 2; + Address += 2; + Len -= 2; + } + + while (Len >= 4) + { + WritePciConfigUlong((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + *(PULONG)Ptr); + Ptr = (char*)Ptr + 4; + Address += 4; + Len -= 4; + } + + if (Len >= 2) + { + WritePciConfigUshort((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + *(PUSHORT)Ptr); + Ptr = (char*)Ptr + 2; + Address += 2; + Len -= 2; + } + + if (Len >= 1) + { + WritePciConfigUchar((UCHAR)BusNumber, + (UCHAR)SlotNumber, + (UCHAR)Address, + *(PUCHAR)Ptr); + Ptr = (char*)Ptr + 1; + Address++; + Len--; + } + + return Length - Len; +} + + +static ULONG +GetBusConfigType(VOID) +{ + ULONG Value; + KIRQL oldIrql; + + DPRINT("GetBusConfigType() called\n"); + + KeAcquireSpinLock(&PciLock, &oldIrql); + + DPRINT("Checking configuration type 1:"); + WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x01); + Value = READ_PORT_ULONG((PULONG)0xCF8); + WRITE_PORT_ULONG((PULONG)0xCF8, 0x80000000); + if (READ_PORT_ULONG((PULONG)0xCF8) == 0x80000000) + { + WRITE_PORT_ULONG((PULONG)0xCF8, Value); + KeReleaseSpinLock(&PciLock, oldIrql); + DPRINT(" Success!\n"); + return 1; + } + WRITE_PORT_ULONG((PULONG)0xCF8, Value); + DPRINT(" Unsuccessful!\n"); + + DPRINT("Checking configuration type 2:"); + WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x00); + WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0x00); + WRITE_PORT_UCHAR((PUCHAR)0xCFA, 0x00); + if (READ_PORT_UCHAR((PUCHAR)0xCF8) == 0x00 && + READ_PORT_UCHAR((PUCHAR)0xCFB) == 0x00) + { + KeReleaseSpinLock(&PciLock, oldIrql); + DPRINT(" Success!\n"); + return 2; + } + KeReleaseSpinLock(&PciLock, oldIrql); + DPRINT(" Unsuccessful!\n"); + + DPRINT("No pci bus found!\n"); + return 0; +} + + +static ULONG STDCALL +HalpGetPciInterruptVector(PVOID BusHandler, + ULONG BusNumber, + ULONG BusInterruptLevel, + ULONG BusInterruptVector, + PKIRQL Irql, + PKAFFINITY Affinity) +{ + ULONG Vector = IRQ2VECTOR(BusInterruptVector); + *Irql = VECTOR2IRQL(Vector); + *Affinity = 0xFFFFFFFF; + return Vector; +} + +static BOOLEAN STDCALL +HalpTranslatePciAddress(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PHYSICAL_ADDRESS BusAddress, + PULONG AddressSpace, + PPHYSICAL_ADDRESS TranslatedAddress) +{ + if (*AddressSpace == 0) + { + /* memory space */ + + } + else if (*AddressSpace == 1) + { + /* io space */ + + } + else + { + /* other */ + return FALSE; + } + + TranslatedAddress->QuadPart = BusAddress.QuadPart; + + return TRUE; +} + +/* + * Find the extent of a PCI decode.. + */ +static ULONG STDCALL +PciSize(ULONG Base, ULONG Mask) +{ + ULONG Size = Mask & Base; /* Find the significant bits */ + Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */ + return Size; +} + +static NTSTATUS STDCALL +HalpAssignPciSlotResources(IN PBUS_HANDLER BusHandler, + IN ULONG BusNumber, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources) +{ + ULONG DataSize; + PCI_COMMON_CONFIG PciConfig; + SIZE_T Address; + SIZE_T ResourceCount; + ULONG Size[PCI_TYPE0_ADDRESSES]; + NTSTATUS Status = STATUS_SUCCESS; + UCHAR Offset; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + + /* FIXME: Should handle 64-bit addresses */ + + DataSize = HalpGetPciData(BusHandler, + BusNumber, + SlotNumber, + &PciConfig, + 0, + PCI_COMMON_HDR_LENGTH); + if (PCI_COMMON_HDR_LENGTH != DataSize) + { + return STATUS_UNSUCCESSFUL; + } + + /* Read the PCI configuration space for the device and store base address and + size information in temporary storage. Count the number of valid base addresses */ + ResourceCount = 0; + for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) + { + if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address]) + { + PciConfig.u.type0.BaseAddresses[Address] = 0; + } + if (0 != PciConfig.u.type0.BaseAddresses[Address]) + { + ResourceCount++; + Offset = FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]); + Status = WritePciConfigUlong((UCHAR)BusNumber, (UCHAR)SlotNumber, Offset, 0xffffffff); + if (! NT_SUCCESS(Status)) + { + WritePciConfigUlong((UCHAR)BusNumber, (UCHAR)SlotNumber, Offset, + PciConfig.u.type0.BaseAddresses[Address]); + return Status; + } + Status = ReadPciConfigUlong((UCHAR)BusNumber, (UCHAR)SlotNumber, + Offset, Size + Address); + if (! NT_SUCCESS(Status)) + { + WritePciConfigUlong((UCHAR)BusNumber, (UCHAR)SlotNumber, Offset, + PciConfig.u.type0.BaseAddresses[Address]); + return Status; + } + Status = WritePciConfigUlong((UCHAR)BusNumber, (UCHAR)SlotNumber, Offset, + PciConfig.u.type0.BaseAddresses[Address]); + if (! NT_SUCCESS(Status)) + { + return Status; + } + } + } + + if (0 != PciConfig.u.type0.InterruptLine) + { + ResourceCount++; + } + + /* Allocate output buffer and initialize */ + *AllocatedResources = ExAllocatePoolWithTag(PagedPool, + sizeof(CM_RESOURCE_LIST) + + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + TAG_PCI); + if (NULL == *AllocatedResources) + { + return STATUS_NO_MEMORY; + } + (*AllocatedResources)->Count = 1; + (*AllocatedResources)->List[0].InterfaceType = PCIBus; + (*AllocatedResources)->List[0].BusNumber = BusNumber; + (*AllocatedResources)->List[0].PartialResourceList.Version = 1; + (*AllocatedResources)->List[0].PartialResourceList.Revision = 1; + (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount; + Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors; + + /* Store configuration information */ + for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) + { + if (0 != PciConfig.u.type0.BaseAddresses[Address]) + { + if (PCI_BASE_ADDRESS_SPACE_MEMORY == + (PciConfig.u.type0.BaseAddresses[Address] & PCI_BASE_ADDRESS_SPACE)) + { + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; /* FIXME Just a guess */ + Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_BASE_ADDRESS_MEM_MASK); + Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_BASE_ADDRESS_MEM_MASK); + } + else if (PCI_BASE_ADDRESS_SPACE_IO == + (PciConfig.u.type0.BaseAddresses[Address] & PCI_BASE_ADDRESS_SPACE)) + { + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ + Descriptor->Flags = CM_RESOURCE_PORT_IO; /* FIXME Just a guess */ + Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_BASE_ADDRESS_IO_MASK; + Descriptor->u.Port.Length = PciSize(Size[Address], PCI_BASE_ADDRESS_IO_MASK & 0xffff); + } + else + { + ASSERT(FALSE); + return STATUS_UNSUCCESSFUL; + } + Descriptor++; + } + } + + if (0 != PciConfig.u.type0.InterruptLine) + { + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->ShareDisposition = CmResourceShareShared; /* FIXME Just a guess */ + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; /* FIXME Just a guess */ + Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine; + Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine; + Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; + + Descriptor++; + } + + ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount); + + /* FIXME: Should store the resources in the registry resource map */ + + return Status; +} + + +VOID +HalpInitPciBus(VOID) +{ + PBUS_HANDLER BusHandler; + + DPRINT("HalpInitPciBus() called.\n"); + + KeInitializeSpinLock (&PciLock); + + BusConfigType = GetBusConfigType(); + if (BusConfigType == 0) + return; + + DPRINT("Bus configuration %lu used\n", BusConfigType); + + /* pci bus (bus 0) handler */ + BusHandler = HalpAllocateBusHandler(PCIBus, + PCIConfiguration, + 0); + BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData; + BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData; + BusHandler->GetInterruptVector = + (pGetInterruptVector)HalpGetPciInterruptVector; + BusHandler->TranslateBusAddress = + (pTranslateBusAddress)HalpTranslatePciAddress; +// BusHandler->AdjustResourceList = +// (pGetSetBusData)HalpAdjustPciResourceList; + BusHandler->AssignSlotResources = + (pAssignSlotResources)HalpAssignPciSlotResources; + if (NULL != HalpHooks.InitPciBus) + { + HalpHooks.InitPciBus(0, BusHandler); + } + + + /* agp bus (bus 1) handler */ + BusHandler = HalpAllocateBusHandler(PCIBus, + PCIConfiguration, + 1); + BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData; + BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData; + BusHandler->GetInterruptVector = + (pGetInterruptVector)HalpGetPciInterruptVector; + BusHandler->TranslateBusAddress = + (pTranslateBusAddress)HalpTranslatePciAddress; +// BusHandler->AdjustResourceList = +// (pGetSetBusData)HalpAdjustPciResourceList; + BusHandler->AssignSlotResources = + (pAssignSlotResources)HalpAssignPciSlotResources; + if (NULL != HalpHooks.InitPciBus) + { + HalpHooks.InitPciBus(1, BusHandler); + } + + + /* PCI bus (bus 2) handler */ + BusHandler = HalpAllocateBusHandler(PCIBus, + PCIConfiguration, + 2); + BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData; + BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData; + BusHandler->GetInterruptVector = + (pGetInterruptVector)HalpGetPciInterruptVector; + BusHandler->TranslateBusAddress = + (pTranslateBusAddress)HalpTranslatePciAddress; +// BusHandler->AdjustResourceList = +// (pGetSetBusData)HalpAdjustPciResourceList; + BusHandler->AssignSlotResources = + (pAssignSlotResources)HalpAssignPciSlotResources; + if (NULL != HalpHooks.InitPciBus) + { + HalpHooks.InitPciBus(2, BusHandler); + } + + DPRINT("HalpInitPciBus() finished.\n"); +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/portio.c b/reactos/hal/halppc/generic/portio.c new file mode 100644 index 00000000000..c665beb1836 --- /dev/null +++ b/reactos/hal/halppc/generic/portio.c @@ -0,0 +1,289 @@ +/* $Id: portio.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/portio.c + * PURPOSE: Port I/O functions + * PROGRAMMER: Eric Kohl (ekohl@abo.rhein-zeitung.de) + * UPDATE HISTORY: + * Created 18/10/99 + */ + +#include +#define NDEBUG +#include + +/* FUNCTIONS ****************************************************************/ + +/* + * This file contains the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl and the "string versions" of the same + * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" + * versions of the single-IO instructions (inb_p/inw_p/..). + * + * This file is not meant to be obfuscating: it's just complicated + * to (a) handle it all in a way that makes gcc able to optimize it + * as well as possible and (b) trying to avoid writing the same thing + * over and over again with slight variations and possibly making a + * mistake somewhere. + */ + +/* + * Thanks to James van Artsdalen for a better timing-fix than + * the two short jumps: using outb's to a nonexistent port seems + * to guarantee better timings even on fast machines. + * + * On the other hand, I'd like to be sure of a non-existent port: + * I feel a bit unsafe about using 0x80 (should be safe, though) + * + * Linus + */ + +#if defined(__GNUC__) + +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") +#else +#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") +#endif + +#elif defined(_MSC_VER) + +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO __asm jmp 1f __asm jmp 1f 1f: +#else +#define __SLOW_DOWN_IO __asm out 0x80, al +#endif + +#else +#error Unknown compiler for inline assembler +#endif + + +#ifdef REALLY_SLOW_IO +#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } +#else +#define SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + +extern int GetPhysByte(int Addr); +extern void SetPhysByte(int Addr, int Val); +extern int GetPhysWord(int Addr); +extern void SetPhysWord(int Addr, int Val); +extern int GetPhys(int Addr); +extern void SetPhys(int Addr, int Val); + +__asm__("\t.globl GetPhys\n" + "GetPhys:\t\n" + "mflr 0\n\t" + "stwu 0,-16(1)\n\t" + "mfmsr 5\n\t" + "xori 3,3,4\n\t" /* Undo effects of LE without swapping */ + "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ + "mtmsr 6\n\t" + "isync\n\t" + "sync\n\t" + "lwz 3,0(3)\n\t" /* Get actual value at phys addr r3 */ + "mtmsr 5\n\t" + "isync\n\t" + "sync\n\t" + "lwz 0,0(1)\n\t" + "addi 1,1,16\n\t" + "mtlr 0\n\t" + "blr" + ); + +__asm__("\t.globl GetPhysWord\n" + "GetPhysWord:\t\n" + "mflr 0\n\t" + "stwu 0,-16(1)\n\t" + "mfmsr 5\n\t" + "xori 3,3,6\n\t" /* Undo effects of LE without swapping */ + "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ + "mtmsr 6\n\t" + "isync\n\t" + "sync\n\t" + "lhz 3,0(3)\n\t" /* Get actual value at phys addr r3 */ + "mtmsr 5\n\t" + "isync\n\t" + "sync\n\t" + "lwz 0,0(1)\n\t" + "addi 1,1,16\n\t" + "mtlr 0\n\t" + "blr" + ); + +__asm__("\t.globl GetPhysByte\n" + "GetPhysByte:\t\n" + "mflr 0\n\t" + "stwu 0,-16(1)\n\t" + "mfmsr 5\n\t" + "xori 3,3,7\n\t" /* Undo effects of LE without swapping */ + "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ + "mtmsr 6\n\t" + "isync\n\t" + "sync\n\t" + "lbz 3,0(3)\n\t" /* Get actual value at phys addr r3 */ + "mtmsr 5\n\t" + "isync\n\t" + "sync\n\t" + "lwz 0,0(1)\n\t" + "addi 1,1,16\n\t" + "mtlr 0\n\t" + "blr" + ); + +__asm__("\t.globl SetPhys\n" + "SetPhys:\t\n" + "mflr 0\n\t" + "stwu 0,-16(1)\n\t" + "mfmsr 5\n\t" + "xori 3,3,4\n\t" /* Undo effects of LE without swapping */ + "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ + "mtmsr 6\n\t" + "sync\n\t" + "eieio\n\t" + "stw 4,0(3)\n\t" /* Set actual value at phys addr r3 */ + "dcbst 0,3\n\t" + "mtmsr 5\n\t" + "sync\n\t" + "eieio\n\t" + "mr 3,4\n\t" + "lwz 0,0(1)\n\t" + "addi 1,1,16\n\t" + "mtlr 0\n\t" + "blr" + ); + +__asm__("\t.globl SetPhysWord\n" + "SetPhysWord:\t\n" + "mflr 0\n\t" + "stwu 0,-16(1)\n\t" + "mfmsr 5\n\t" + "xori 3,3,6\n\t" /* Undo effects of LE without swapping */ + "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ + "mtmsr 6\n\t" + "sync\n\t" + "eieio\n\t" + "sth 4,0(3)\n\t" /* Set actual value at phys addr r3 */ + "dcbst 0,3\n\t" + "mtmsr 5\n\t" + "sync\n\t" + "eieio\n\t" + "mr 3,4\n\t" + "lwz 0,0(1)\n\t" + "addi 1,1,16\n\t" + "mtlr 0\n\t" + "blr" + ); + +__asm__("\t.globl SetPhysByte\n" + "SetPhysByte:\t\n" + "mflr 0\n\t" + "stwu 0,-16(1)\n\t" + "mfmsr 5\n\t" + "xori 3,3,7\n\t" /* Undo effects of LE without swapping */ + "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ + "mtmsr 6\n\t" + "sync\n\t" + "eieio\n\t" + "stb 4,0(3)\n\t" /* Set actual value at phys addr r3 */ + "dcbst 0,3\n\t" + "mtmsr 5\n\t" + "sync\n\t" + "eieio\n\t" + "mr 3,4\n\t" + "lwz 0,0(1)\n\t" + "addi 1,1,16\n\t" + "mtlr 0\n\t" + "blr" + ); + +VOID STDCALL +READ_PORT_BUFFER_UCHAR (PUCHAR Port, + PUCHAR Buffer, + ULONG Count) +{ + while(Count--) { *Buffer++ = GetPhysByte((ULONG)Port); } +} + +VOID STDCALL +READ_PORT_BUFFER_USHORT (PUSHORT Port, + PUSHORT Buffer, + ULONG Count) +{ + while(Count--) { *Buffer++ = GetPhysWord((ULONG)Port); } +} + +VOID STDCALL +READ_PORT_BUFFER_ULONG (PULONG Port, + PULONG Buffer, + ULONG Count) +{ + while(Count--) { *Buffer++ = GetPhys((ULONG)Port); } +} + +UCHAR STDCALL +READ_PORT_UCHAR (PUCHAR Port) +{ + return GetPhys((ULONG)Port); +} + +USHORT STDCALL +READ_PORT_USHORT (PUSHORT Port) +{ + return GetPhysWord((ULONG)Port); +} + +ULONG STDCALL +READ_PORT_ULONG (PULONG Port) +{ + return GetPhys((ULONG)Port); +} + +VOID STDCALL +WRITE_PORT_BUFFER_UCHAR (PUCHAR Port, + PUCHAR Buffer, + ULONG Count) +{ + while(Count--) { SetPhysByte((ULONG)Port, *Buffer++); } +} + +VOID STDCALL +WRITE_PORT_BUFFER_USHORT (PUSHORT Port, + PUSHORT Buffer, + ULONG Count) +{ + while(Count--) { SetPhysWord((ULONG)Port, *Buffer++); } +} + +VOID STDCALL +WRITE_PORT_BUFFER_ULONG (PULONG Port, + PULONG Buffer, + ULONG Count) +{ + while(Count--) { SetPhys((ULONG)Port, *Buffer++); } +} + +VOID STDCALL +WRITE_PORT_UCHAR (PUCHAR Port, + UCHAR Value) +{ + SetPhysByte((ULONG)Port, Value); +} + +VOID STDCALL +WRITE_PORT_USHORT (PUSHORT Port, + USHORT Value) +{ + SetPhysWord((ULONG)Port, Value); +} + +VOID STDCALL +WRITE_PORT_ULONG (PULONG Port, + ULONG Value) +{ + SetPhys((ULONG)Port, Value); +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/processor.c b/reactos/hal/halppc/generic/processor.c new file mode 100644 index 00000000000..25867253203 --- /dev/null +++ b/reactos/hal/halppc/generic/processor.c @@ -0,0 +1,50 @@ +/* $Id: processor.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/processor.c + * PURPOSE: Intel MultiProcessor specification support + * PROGRAMMER: David Welch (welch@cwcom.net) + * Casper S. Hornstrup (chorns@users.sourceforge.net) + * NOTES: Parts adapted from linux SMP code + * UPDATE HISTORY: + * 22/05/1998 DW Created + * 12/04/2001 CSH Added MultiProcessor specification support + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +VOID STDCALL +HalInitializeProcessor(ULONG ProcessorNumber, + PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + DPRINT("HalInitializeProcessor(%lu %p)\n", ProcessorNumber, LoaderBlock); + /* Set default IDR */ + KeGetPcr()->IDR = 0xFFFFFFFB; + KeGetPcr()->StallScaleFactor = INITIAL_STALL_COUNT; +} + +BOOLEAN STDCALL +HalAllProcessorsStarted (VOID) +{ + DPRINT("HalAllProcessorsStarted()\n"); + + return TRUE; +} + +BOOLEAN STDCALL +HalStartNextProcessor(ULONG Unknown1, + ULONG ProcessorStack) +{ + DPRINT("HalStartNextProcessor(0x%lx 0x%lx)\n", Unknown1, ProcessorStack); + + return TRUE; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/pwroff.c b/reactos/hal/halppc/generic/pwroff.c new file mode 100644 index 00000000000..cf6be7555b9 --- /dev/null +++ b/reactos/hal/halppc/generic/pwroff.c @@ -0,0 +1,121 @@ +/* $Id: pwroff.c 23907 2006-09-04 05:52:23Z arty $ + * + * FILE : reactos/hal/x86/apm.c + * DESCRIPTION: Turn CPU off... + * PROJECT : ReactOS Operating System + * AUTHOR : D. Lindauer (July 11 1997) + * NOTE : This program is public domain + * REVISIONS : + * 1999-12-26 + */ + +#define APM_FUNCTION_AVAILABLE 0x5300 +#define APM_FUNCTION_CONNREAL 0x5301 +#define APM_FUNCTION_POWEROFF 0x5307 +#define APM_FUNCTION_ENABLECPU 0x530d +#define APM_FUNCTION_ENABLEAPM 0x530e + +#define APM_DEVICE_BIOS 0 +#define APM_DEVICE_ALL 1 + +#define APM_MODE_DISABLE 0 +#define APM_MODE_ENABLE 1 + + + +#if defined(__GNUC__) + +nopm db 'No power management functionality',10,13,'$' +errmsg db 'Power management error',10,13,'$' +wrongver db 'Need APM version 1.1 or better',10,13,'$' +; +; Entry point +; +go: + mov dx,offset nopm + jc error + cmp ax,101h ; See if version 1.1 or greater + mov dx,offset wrongver + jc error + + mov [ver],ax + mov ax,5301h ; Do a real mode connection + mov bx,0 ; device = BIOS + int 15h + jnc noconerr + + cmp ah,2 ; Pass if already connected + mov dx,offset errmsg ; else error + jnz error +noconerr: + mov ax,530eh ; Enable latest version of APM + mov bx,0 ; device = BIOS + mov cx,[ver] ; version + int 15h + mov dx,offset errmsg + jc error + + mov ax,530dh ; Now engage and enable CPU management + mov bx,1 ; device = all + mov cx,1 ; enable + int 15h + mov dx,offset errmsg + jc error + + mov ax,530fh + mov bx,1 ; device = ALL + mov cx,1 ; enable + int 15h + mov dx,offset errmsg + jc error + + mov dx,offset errmsg +error: + call print + mov ax,4c01h + int 21h + int 3 + end start + + +BOOLEAN +ApmCall ( + DWORD Function, + DWORD Device, + DWORD Mode + ) +{ + /* AX <== Function */ + /* BX <== Device */ + /* CX <== Mode */ + __asm__("int 21\n"); /* 0x15 */ +} + +#elif defined(_MSC_VER) +#else +#error Unknown compiler for inline assembler +#endif + + +BOOLEAN +HalPowerOff (VOID) +{ + ApmCall ( + APM_FUNCTION_AVAILABLE, + APM_DEVICE_BIOS, + 0 + ); + ApmCall ( + APM_FUNCTION_ENABLEAPM, + ); + /* Shutdown CPU */ + ApmCall ( + APM_FUNCTION_POWEROFF, + APM_DEVICE_ALL, + 3 + ); + return TRUE; +} + + +/* EOF */ diff --git a/reactos/hal/halppc/generic/reboot.c b/reactos/hal/halppc/generic/reboot.c new file mode 100644 index 00000000000..89ab5c0d221 --- /dev/null +++ b/reactos/hal/halppc/generic/reboot.c @@ -0,0 +1,41 @@ +/* $Id: reboot.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/reboot.c + * PURPOSE: Reboot functions. + * PROGRAMMER: Eric Kohl (ekohl@abo.rhein-zeitung.de) + * UPDATE HISTORY: + * Created 11/10/99 + */ + +#include +#define NDEBUG +#include + +typedef void (*void_fun)(); +static VOID +HalReboot (VOID) +{ + void_fun reset_vector = (void_fun)0xfff00100; + reset_vector(); +} + + +VOID STDCALL +HalReturnToFirmware ( + FIRMWARE_REENTRY Action + ) +{ + if (Action == HalHaltRoutine) + { + DbgPrint ("HalReturnToFirmware called!\n"); + DbgBreakPoint (); + } + else if (Action == HalRebootRoutine) + { + HalReboot (); + } +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/resource.c b/reactos/hal/halppc/generic/resource.c new file mode 100644 index 00000000000..acf17ff151d --- /dev/null +++ b/reactos/hal/halppc/generic/resource.c @@ -0,0 +1,31 @@ +/* $Id: resource.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/resource.c + * PURPOSE: Miscellaneous resource functions + * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + +/* FUNCTIONS ****************************************************************/ + +VOID STDCALL +HalReportResourceUsage(VOID) +{ + /* + * FIXME: Report all resources used by hal. + * Calls IoReportHalResourceUsage() + */ + + /* Initialize PCI bus. */ + HalpInitPciBus (); +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/spinlock.c b/reactos/hal/halppc/generic/spinlock.c new file mode 100644 index 00000000000..30d66bb230b --- /dev/null +++ b/reactos/hal/halppc/generic/spinlock.c @@ -0,0 +1,191 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/halx86/up/spinlock.c + * PURPOSE: Implements spinlocks + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ****************************************************************/ + +#include +#define NDEBUG +#include + +#undef KeAcquireSpinLock +#undef KeReleaseSpinLock +#undef KeLowerIrql +#undef KeRaiseIrql + +/* FUNCTIONS ***************************************************************/ + +/* + * @implemented + */ +VOID +NTAPI +KeLowerIrql(KIRQL NewIrql) +{ + /* Call the fastcall function */ + KfLowerIrql(NewIrql); +} + +/* + * @implemented + */ +VOID +NTAPI +KeRaiseIrql(KIRQL NewIrql, + PKIRQL OldIrql) +{ + /* Call the fastcall function */ + *OldIrql = KfRaiseIrql(NewIrql); +} + +/* + * @implemented + */ +VOID +NTAPI +KeAcquireSpinLock(PKSPIN_LOCK SpinLock, + PKIRQL OldIrql) +{ + /* Call the fastcall function */ + *OldIrql = KfAcquireSpinLock(SpinLock); +} + +/* + * @implemented + */ +KIRQL +FASTCALL +KeAcquireSpinLockRaiseToSynch(PKSPIN_LOCK SpinLock) +{ + /* Simply raise to dispatch */ + return KfRaiseIrql(DISPATCH_LEVEL); +} + +/* + * @implemented + */ +VOID +NTAPI +KeReleaseSpinLock(PKSPIN_LOCK SpinLock, + KIRQL NewIrql) +{ + /* Call the fastcall function */ + KfReleaseSpinLock(SpinLock, NewIrql); +} + +/* + * @implemented + */ +KIRQL +FASTCALL +KfAcquireSpinLock(PKSPIN_LOCK SpinLock) +{ + /* Simply raise to dispatch */ + return KfRaiseIrql(DISPATCH_LEVEL); +} + +/* + * @implemented + */ +VOID +FASTCALL +KfReleaseSpinLock(PKSPIN_LOCK SpinLock, + KIRQL OldIrql) +{ + /* Simply lower IRQL back */ + KfLowerIrql(OldIrql); +} + +/* + * @implemented + */ +KIRQL +FASTCALL +KeAcquireQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle) +{ + /* Simply raise to dispatch */ + return KfRaiseIrql(DISPATCH_LEVEL); +} + +/* + * @implemented + */ +KIRQL +FASTCALL +KeAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber) +{ + /* Simply raise to dispatch */ + return KfRaiseIrql(DISPATCH_LEVEL); +} + +/* + * @implemented + */ +VOID +FASTCALL +KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock, + IN PKLOCK_QUEUE_HANDLE LockHandle) +{ + /* Simply raise to dispatch */ + LockHandle->OldIrql = KfRaiseIrql(DISPATCH_LEVEL); +} + +/* + * @implemented + */ +VOID +FASTCALL +KeReleaseQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle, + IN KIRQL OldIrql) +{ + /* Simply lower IRQL back */ + KfLowerIrql(OldIrql); +} + +/* + * @implemented + */ +VOID +FASTCALL +KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle) +{ + /* Simply lower IRQL back */ + KfLowerIrql(LockHandle->OldIrql); +} + +/* + * @implemented + */ +BOOLEAN +FASTCALL +KeTryToAcquireQueuedSpinLockRaiseToSynch(IN PKLOCK_QUEUE_HANDLE LockHandle, + IN PKIRQL OldIrql) +{ + /* Simply raise to dispatch */ + *OldIrql = KfRaiseIrql(DISPATCH_LEVEL); + + /* Always return true on UP Machines */ + return TRUE; +} + +/* + * @implemented + */ +BOOLEAN +FASTCALL +KeTryToAcquireQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle, + IN PKIRQL OldIrql) +{ + /* Simply raise to dispatch */ + *OldIrql = KfRaiseIrql(DISPATCH_LEVEL); + + /* Always return true on UP Machines */ + return TRUE; +} + + +/* EOF */ diff --git a/reactos/hal/halppc/generic/sysbus.c b/reactos/hal/halppc/generic/sysbus.c new file mode 100644 index 00000000000..4955b122cfd --- /dev/null +++ b/reactos/hal/halppc/generic/sysbus.c @@ -0,0 +1,66 @@ +/* $Id: sysbus.c 23907 2006-09-04 05:52:23Z arty $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/sysbus.c + * PURPOSE: System bus handler functions + * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + * UPDATE HISTORY: + * 09/04/2000 Created + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + +/* FUNCTIONS ****************************************************************/ + +ULONG STDCALL +HalpGetSystemInterruptVector(PVOID BusHandler, + ULONG BusNumber, + ULONG BusInterruptLevel, + ULONG BusInterruptVector, + PKIRQL Irql, + PKAFFINITY Affinity) +{ + ULONG Vector = IRQ2VECTOR(BusInterruptVector); + *Irql = VECTOR2IRQL(Vector); + *Affinity = 0xFFFFFFFF; + return Vector; +} + + +BOOLEAN STDCALL +HalpTranslateSystemBusAddress(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PHYSICAL_ADDRESS BusAddress, + PULONG AddressSpace, + PPHYSICAL_ADDRESS TranslatedAddress) +{ + ULONG BaseAddress = 0; + + if (*AddressSpace == 0) + { + /* memory space */ + + } + else if (*AddressSpace == 1) + { + /* io space */ + + } + else + { + /* other */ + return FALSE; + } + + TranslatedAddress->QuadPart = BusAddress.QuadPart + BaseAddress; + + return TRUE; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/sysinfo.c b/reactos/hal/halppc/generic/sysinfo.c new file mode 100644 index 00000000000..a5ccfeb1be7 --- /dev/null +++ b/reactos/hal/halppc/generic/sysinfo.c @@ -0,0 +1,74 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/sysinfo.c + * PURPOSE: Getting system information + * PROGRAMMER: David Welch (welch@mcmail.com) + * UPDATE HISTORY: + * Created 22/05/98 + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS STDCALL +HalpQuerySystemInformation(IN HAL_QUERY_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN OUT PVOID Buffer, + OUT PULONG ReturnedLength) +{ + ULONG DataLength; + NTSTATUS Status; + + DPRINT1("HalpQuerySystemInformation() called\n"); + + *ReturnedLength = 0; + + DataLength = 0; + + switch(InformationClass) + { +#if 0 + case HalInstalledBusInformation: + Status = HalpQueryBusInformation(BufferSize, + Buffer, + ReturnedLength); + break; +#endif + + default: + DataLength = 0; + Status = STATUS_INVALID_LEVEL; + break; + } + + if (DataLength != 0) + { + if (DataLength > BufferSize) + DataLength = BufferSize; + +// RtlCopyMemory(); + + *ReturnedLength = DataLength; + } + + return(Status); +} + + +#if 0 +NTSTATUS +HalpSetSystemInformation(VOID) +{ + UNIMPLEMENTED; +} +#endif + +/* EOF */ diff --git a/reactos/hal/halppc/generic/systimer.S b/reactos/hal/halppc/generic/systimer.S new file mode 100644 index 00000000000..285686675a7 --- /dev/null +++ b/reactos/hal/halppc/generic/systimer.S @@ -0,0 +1,48 @@ +/* + * FILE: hal/halx86/generic/timer.S + * COPYRIGHT: See COPYING in the top level directory + * PURPOSE: System Timer Interrupt and Management + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ******************************************************************/ + +#include +#include +.intel_syntax noprefix + +/* FUNCTIONS *****************************************************************/ + +.globl _HalpClockInterrupt@0 +.func HalpClockInterrupt@0 +_HalpClockInterrupt@0: + + /* Enter trap */ + INT_PROLOG Hci, DoPushFakeErrorCode + + /* Push vector and make stack for IRQL */ + push 0x30 + sub esp, 4 + + /* Begin the interrupt */ + push esp + push 0x30 + push CLOCK2_LEVEL + call _HalBeginSystemInterrupt@12 + + /* Check if it's spurious */ + or al, al + jz Spurious + + /* Do a tick */ + mov eax, 100000 + jmp _KeUpdateSystemTime@0 + +Spurious: + + /* Exit the interrupt */ + add esp, 8 + mov esi, $ + jmp _Kei386EoiHelper@0 +.endfunc + diff --git a/reactos/hal/halppc/generic/time.c b/reactos/hal/halppc/generic/time.c new file mode 100644 index 00000000000..bb81cc01cec --- /dev/null +++ b/reactos/hal/halppc/generic/time.c @@ -0,0 +1,102 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/time.c + * PURPOSE: Getting time information + * UPDATE HISTORY: + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + + +/* MACROS and CONSTANTS ******************************************************/ + +/* macro BCD_INT : convert bcd to int */ +#define BCD_INT(bcd) (((bcd & 0xf0) >> 4) * 10 + (bcd &0x0f)) + +/* macro INT_BCD : convert int to bcd */ +#define INT_BCD(int) (((int / 10) << 4) + (int % 10)) + + +#define RTC_REGISTER_A 0x0A +#define RTC_REG_A_UIP 0x80 /* Update In Progress bit */ + +#define RTC_REGISTER_B 0x0B + +#define RTC_REGISTER_CENTURY 0x32 + +/* GLOBALS ******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN STDCALL +HalQueryRealTimeClock(PTIME_FIELDS Time) +{ + return TRUE; +} + + +VOID STDCALL +HalSetRealTimeClock(PTIME_FIELDS Time) +{ +} + + +BOOLEAN STDCALL +HalGetEnvironmentVariable(PCH Name, + USHORT ValueLength, + PCH Value) +{ + strncpy(Value, "TRUE", ValueLength); + return TRUE; +} + + +BOOLEAN STDCALL +HalSetEnvironmentVariable(PCH Name, + PCH Value) +{ + return TRUE; +} + + +ULONG STDCALL +HalpGetCmosData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + DPRINT("HalpGetCmosData() called.\n"); + DPRINT(" BusNumber %lu\n", BusNumber); + DPRINT(" SlotNumber %lu\n", SlotNumber); + DPRINT(" Offset 0x%lx\n", Offset); + DPRINT(" Length 0x%lx\n", Length); + + return 0; +} + + +ULONG STDCALL +HalpSetCmosData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length) +{ + DPRINT("HalpSetCmosData() called.\n"); + DPRINT(" BusNumber %lu\n", BusNumber); + DPRINT(" SlotNumber %lu\n", SlotNumber); + DPRINT(" Offset 0x%lx\n", Offset); + DPRINT(" Length 0x%lx\n", Length); + + return 0; +} + +/* EOF */ diff --git a/reactos/hal/halppc/generic/timer.c b/reactos/hal/halppc/generic/timer.c new file mode 100644 index 00000000000..9df30825631 --- /dev/null +++ b/reactos/hal/halppc/generic/timer.c @@ -0,0 +1,205 @@ +/* + * ReactOS kernel + * Copyright (C) 2000 David Welch + * Copyright (C) 1999 Gareth Owen , Ramon von Handel + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This software 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 software 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 software; see the file COPYING. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + */ +/* $Id: timer.c 23907 2006-09-04 05:52:23Z arty $ + * + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/hal/x86/udelay.c + * PURPOSE: Busy waiting + * PROGRAMMER: David Welch (david.welch@seh.ox.ac.uk) + * UPDATE HISTORY: + * 06/11/99 Created + */ + +/* INCLUDES ***************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ******************************************************************/ + +#define TMR_CTRL 0x43 /* I/O for control */ +#define TMR_CNT0 0x40 /* I/O for counter 0 */ +#define TMR_CNT1 0x41 /* I/O for counter 1 */ +#define TMR_CNT2 0x42 /* I/O for counter 2 */ + +#define TMR_SC0 0 /* Select channel 0 */ +#define TMR_SC1 0x40 /* Select channel 1 */ +#define TMR_SC2 0x80 /* Select channel 2 */ + +#define TMR_LOW 0x10 /* RW low byte only */ +#define TMR_HIGH 0x20 /* RW high byte only */ +#define TMR_BOTH 0x30 /* RW both bytes */ + +#define TMR_MD0 0 /* Mode 0 */ +#define TMR_MD1 0x2 /* Mode 1 */ +#define TMR_MD2 0x4 /* Mode 2 */ +#define TMR_MD3 0x6 /* Mode 3 */ +#define TMR_MD4 0x8 /* Mode 4 */ +#define TMR_MD5 0xA /* Mode 5 */ + +#define TMR_BCD 1 /* BCD mode */ + +#define TMR_LATCH 0 /* Latch command */ + +#define TMR_READ 0xF0 /* Read command */ +#define TMR_CNT 0x20 /* CNT bit (Active low, subtract it) */ +#define TMR_STAT 0x10 /* Status bit (Active low, subtract it) */ +#define TMR_CH2 0x8 /* Channel 2 bit */ +#define TMR_CH1 0x4 /* Channel 1 bit */ +#define TMR_CH0 0x2 /* Channel 0 bit */ + +#define MILLISEC 10 /* Number of millisec between interrupts */ +#define HZ (1000 / MILLISEC) /* Number of interrupts per second */ +#define CLOCK_TICK_RATE 1193182 /* Clock frequency of the timer chip */ +#define LATCH (CLOCK_TICK_RATE / HZ) /* Count to program into the timer chip */ +#define PRECISION 8 /* Number of bits to calibrate for delay loop */ + +static BOOLEAN UdelayCalibrated = FALSE; + +/* FUNCTIONS **************************************************************/ + +static BOOLEAN PPCGetEEBit() +{ + ULONG Msr; + __asm__("mfmsr %0" : "=r" (Msr)); + return (Msr & 0x8000) != 0; +} + +/* + * NOTE: This function MUST NOT be optimized by the compiler! + * If it is, it obviously will not delay AT ALL, and the system + * will appear completely frozen at boot since + * HalpCalibrateStallExecution will never return. + * There are three options to stop optimization: + * 1. Use a volatile automatic variable. Making it delay quite a bit + * due to memory accesses, and keeping the code portable. However, + * as this involves memory access it depends on both the CPU cache, + * e.g. if the stack used is already in a cache line or not, and + * whether or not we're MP. If MP, another CPU could (probably would) + * also access RAM at the same time - making the delay imprecise. + * 2. Use compiler-specific #pragma's to disable optimization. + * 3. Use inline assembly, making it equally unportable as #2. + * For supported compilers we use inline assembler. For the others, + * portable plain C. + */ +DECLSPEC_NOINLINE VOID STDCALL +__KeStallExecutionProcessor(ULONG Loops) +{ + ULONG DecInit, DecCount; + if (!Loops) + { + return; + } + __asm__("mfdec %0" : "=r" (DecInit)); + do { + __asm__("mfdec %0" : "=r" (DecCount)); + } while((DecCount - DecInit) < Loops); +} + +VOID +STDCALL +KeStallExecutionProcessor(ULONG Microseconds) +{ + PKIPCR Pcr = (PKIPCR)KeGetPcr(); + LARGE_INTEGER EndCount, CurrentCount; + ULONG NewCount; + __asm__("mfdec %0" : "=r" (NewCount)); + EndCount.QuadPart = NewCount + Microseconds * (ULONGLONG)Pcr->Prcb->MHz; + do + { + __asm__("mfdec %0" : "=r" (NewCount)); + if(NewCount < CurrentCount.LowPart) + CurrentCount.HighPart++; + CurrentCount.LowPart = NewCount; + } + while (CurrentCount.QuadPart < EndCount.QuadPart); +} + +VOID HalpCalibrateStallExecution(VOID) +{ + PKIPCR Pcr; + + if (UdelayCalibrated) + { + return; + } + + UdelayCalibrated = TRUE; + Pcr = (PKIPCR)KeGetPcr(); + + // XXX arty FIXME + /* Pcr->Prcb.MHz = (ULONG)(EndCount.QuadPart - StartCount.QuadPart) / 10000; */ + Pcr->Prcb->MHz = 300; + DPRINT1("%luMHz\n", Pcr->Prcb->MHz); +} + + +VOID STDCALL +HalCalibratePerformanceCounter(ULONG Count) +{ + BOOLEAN InterruptsEnabled = PPCGetEEBit(); + + /* save flags and disable interrupts */ + _disable(); + + __KeStallExecutionProcessor(Count); + + /* restore flags */ + if(InterruptsEnabled) + _enable(); +} + + +LARGE_INTEGER +STDCALL +KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFreq) +/* + * FUNCTION: Queries the finest grained running count available in the system + * ARGUMENTS: + * PerformanceFreq (OUT) = The routine stores the number of + * performance counter ticks per second here + * RETURNS: The number of performance counter ticks since boot + */ +{ + PKIPCR Pcr; + LARGE_INTEGER Value; + BOOLEAN InterruptsEnabled = PPCGetEEBit(); + + _disable(); + + Pcr = (PKIPCR)KeGetPcr(); + + if (NULL != PerformanceFreq) + { + PerformanceFreq->QuadPart = Pcr->Prcb->MHz * (ULONGLONG)1000000; + } + __asm__("mfdec %0" : "=r" (Value.LowPart)); + + if(InterruptsEnabled) + _enable(); + + return Value; +} + +/* EOF */ diff --git a/reactos/hal/halppc/include/apic.h b/reactos/hal/halppc/include/apic.h new file mode 100644 index 00000000000..7454c210f72 --- /dev/null +++ b/reactos/hal/halppc/include/apic.h @@ -0,0 +1,214 @@ +/* + * + */ + +#ifndef __INTERNAL_HAL_APIC_H +#define __INTERNAL_HAL_APIC_H + +#define APIC_DEFAULT_BASE 0xFEE00000 /* Default Local APIC Base Register Address */ + +/* APIC Register Address Map */ +#define APIC_ID 0x0020 /* Local APIC ID Register (R/W) */ +#define APIC_VER 0x0030 /* Local APIC Version Register (R) */ +#define APIC_TPR 0x0080 /* Task Priority Register (R/W) */ +#define APIC_APR 0x0090 /* Arbitration Priority Register (R) */ +#define APIC_PPR 0x00A0 /* Processor Priority Register (R) */ +#define APIC_EOI 0x00B0 /* EOI Register (W) */ +#define APIC_LDR 0x00D0 /* Logical Destination Register (R/W) */ +#define APIC_DFR 0x00E0 /* Destination Format Register (0-27 R, 28-31 R/W) */ +#define APIC_SIVR 0x00F0 /* Spurious Interrupt Vector Register (0-3 R, 4-9 R/W) */ +#define APIC_ISR 0x0100 /* Interrupt Service Register 0-255 (R) */ +#define APIC_TMR 0x0180 /* Trigger Mode Register 0-255 (R) */ +#define APIC_IRR 0x0200 /* Interrupt Request Register 0-255 (r) */ +#define APIC_ESR 0x0280 /* Error Status Register (R) */ +#define APIC_ICR0 0x0300 /* Interrupt Command Register 0-31 (R/W) */ +#define APIC_ICR1 0x0310 /* Interrupt Command Register 32-63 (R/W) */ +#define APIC_LVTT 0x0320 /* Local Vector Table (Timer) (R/W) */ +#define APIC_LVTTHMR 0x0330 +#define APIC_LVTPC 0x0340 /* Performance Counter LVT (R/W) */ +#define APIC_LINT0 0x0350 /* Local Vector Table (LINT0) (R/W) */ +#define APIC_LINT1 0x0360 /* Local Vector Table (LINT1) (R/W) */ +#define APIC_LVT3 0x0370 /* Local Vector Table (Error) (R/W) */ +#define APIC_ICRT 0x0380 /* Initial Count Register for Timer (R/W) */ +#define APIC_CCRT 0x0390 /* Current Count Register for Timer (R) */ +#define APIC_TDCR 0x03E0 /* Timer Divide Configuration Register (R/W) */ + +#define APIC_ID_MASK (0xF << 24) +#define GET_APIC_ID(x) (((x) & APIC_ID_MASK) >> 24) +#define GET_APIC_LOGICAL_ID(x) (((x)>>24)&0xFF) +#define APIC_VER_MASK 0xFF00FF +#define GET_APIC_VERSION(x) ((x) & 0xFF) +#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFF) + +#define APIC_TPR_PRI 0xFF +#define APIC_TPR_INT 0xF0 +#define APIC_TPR_SUB 0xF +#define APIC_TPR_MAX 0xFF /* Maximum priority */ +#define APIC_TPR_MIN 0x20 /* Minimum priority */ + +#define APIC_LDR_MASK (0xFF << 24) + +#define APIC_SIVR_ENABLE (0x1 << 8) +#define APIC_SIVR_FOCUS (0x1 << 9) + +#define APIC_ESR_MASK (0xFE << 0) /* Error Mask */ + +#define APIC_ICR0_VECTOR (0xFF << 0) /* Vector */ +#define APIC_ICR0_DM (0x7 << 8) /* Delivery Mode */ +#define APIC_ICR0_DESTM (0x1 << 11) /* Destination Mode */ +#define APIC_ICR0_DS (0x1 << 12) /* Delivery Status */ +#define APIC_ICR0_LEVEL (0x1 << 14) /* Level */ +#define APIC_ICR0_TM (0x1 << 15) /* Trigger Mode */ +#define APIC_ICR0_DESTS (0x3 << 18) /* Destination Shorthand */ + +/* Delivery Modes */ +#define APIC_DM_FIXED (0x0 << 8) +#define APIC_DM_LOWEST (0x1 << 8) +#define APIC_DM_SMI (0x2 << 8) +#define APIC_DM_REMRD (0x3 << 8) +#define APIC_DM_NMI (0x4 << 8) +#define APIC_DM_INIT (0x5 << 8) +#define APIC_DM_STARTUP (0x6 << 8) +#define APIC_DM_EXTINT (0x7 << 8) +#define GET_APIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7) +#define SET_APIC_DELIVERY_MODE(x,y) (((x) & ~0x700) | ((y) << 8)) + +/* Destination Shorthand values */ +#define APIC_ICR0_DESTS_FIELD (0x0 << 0) +#define APIC_ICR0_DESTS_SELF (0x1 << 18) +#define APIC_ICR0_DESTS_ALL (0x2 << 18) +#define APIC_ICR0_DESTS_ALL_BUT_SELF (0x3 << 18) + +#define APIC_ICR0_LEVEL_DEASSERT (0x0 << 14) /* Deassert level */ +#define APIC_ICR0_LEVEL_ASSERT (0x1 << 14) /* Assert level */ + +#define GET_APIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) +#define SET_APIC_DEST_FIELD(x) (((x) & 0xFF) << 24) + +#define GET_APIC_TIMER_BASE(x) (((x) >> 18) & 0x3) +#define SET_APIC_TIMER_BASE(x) ((x) << 18) +#define APIC_TIMER_BASE_CLKIN 0x0 +#define APIC_TIMER_BASE_TMBASE 0x1 +#define APIC_TIMER_BASE_DIV 0x2 + +#define APIC_LVT_VECTOR (0xFF << 0) /* Vector */ +#define APIC_LVT_DS (0x1 << 12) /* Delivery Status */ +#define APIC_LVT_REMOTE_IRR (0x1 << 14) /* Remote IRR */ +#define APIC_LVT_LEVEL_TRIGGER (0x1 << 15) /* Lvel Triggered */ +#define APIC_LVT_MASKED (0x1 << 16) /* Mask */ +#define APIC_LVT_PERIODIC (0x1 << 17) /* Timer Mode */ + +#define APIC_LVT3_DM (0x7 << 8) +#define APIC_LVT3_IIPP (0x1 << 13) +#define APIC_LVT3_TM (0x1 << 15) +#define APIC_LVT3_MASKED (0x1 << 16) +#define APIC_LVT3_OS (0x1 << 17) + +#define APIC_TDCR_TMBASE (0x1 << 2) +#define APIC_TDCR_MASK 0x0F +#define APIC_TDCR_2 0x00 +#define APIC_TDCR_4 0x01 +#define APIC_TDCR_8 0x02 +#define APIC_TDCR_16 0x03 +#define APIC_TDCR_32 0x08 +#define APIC_TDCR_64 0x09 +#define APIC_TDCR_128 0x0A +#define APIC_TDCR_1 0x0B + +#define APIC_LVT_VECTOR (0xFF << 0) /* Vector */ +#define APIC_LVT_DS (0x1 << 12) /* Delivery Status */ +#define APIC_LVT_REMOTE_IRR (0x1 << 14) /* Remote IRR */ +#define APIC_LVT_LEVEL_TRIGGER (0x1 << 15) /* Lvel Triggered */ +#define APIC_LVT_MASKED (0x1 << 16) /* Mask */ +#define APIC_LVT_PERIODIC (0x1 << 17) /* Timer Mode */ + +#define APIC_LVT3_DM (0x7 << 8) +#define APIC_LVT3_IIPP (0x1 << 13) +#define APIC_LVT3_TM (0x1 << 15) +#define APIC_LVT3_MASKED (0x1 << 16) +#define APIC_LVT3_OS (0x1 << 17) + +#define APIC_TDCR_TMBASE (0x1 << 2) +#define APIC_TDCR_MASK 0x0F +#define APIC_TDCR_2 0x00 +#define APIC_TDCR_4 0x01 +#define APIC_TDCR_8 0x02 +#define APIC_TDCR_16 0x03 +#define APIC_TDCR_32 0x08 +#define APIC_TDCR_64 0x09 +#define APIC_TDCR_128 0x0A +#define APIC_TDCR_1 0x0B + +#define APIC_TARGET_SELF 0x100 +#define APIC_TARGET_ALL 0x200 +#define APIC_TARGET_ALL_BUT_SELF 0x300 + +#define APIC_INTEGRATED(version) (version & 0xF0) + +typedef enum { + amPIC = 0, /* IMCR and PIC compatibility mode */ + amVWIRE /* Virtual Wire compatibility mode */ +} APIC_MODE; + +#ifdef CONFIG_SMP +#define MAX_CPU 32 +#else +#define MAX_CPU 1 +#endif + +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xEF + +#define IPI_VECTOR 0xFB +#define ERROR_VECTOR 0xFE +#define SPURIOUS_VECTOR 0xFF /* Must be 0xXF */ + +/* CPU flags */ +#define CPU_USABLE 0x01 /* 1 if the CPU is usable (ie. can be used) */ +#define CPU_ENABLED 0x02 /* 1 if the CPU is enabled */ +#define CPU_BSP 0x04 /* 1 if the CPU is the bootstrap processor */ +#define CPU_TSC 0x08 /* 1 if the CPU has a time stamp counter */ + +typedef struct _CPU_INFO +{ + UCHAR Flags; /* CPU flags */ + UCHAR APICId; /* Local APIC ID */ + UCHAR APICVersion; /* Local APIC version */ +// UCHAR MaxLVT; /* Number of LVT registers */ + ULONG BusSpeed; /* BUS speed */ + ULONG CoreSpeed; /* Core speed */ + UCHAR Padding[16-12]; /* Padding to 16-byte */ +} CPU_INFO, *PCPU_INFO; + +extern ULONG CPUCount; /* Total number of CPUs */ +extern ULONG BootCPU; /* Bootstrap processor */ +extern ULONG OnlineCPUs; /* Bitmask of online CPUs */ +extern CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */ + +/* Prototypes */ + +__inline VOID APICWrite(ULONG Offset, ULONG Value); +__inline ULONG APICRead(ULONG Offset); +VOID APICSendIPI(ULONG Target, ULONG Mode); +VOID APICSetup(VOID); +VOID HaliInitBSP(VOID); +VOID APICSyncArbIDs(VOID); +__inline VOID APICSendEOI(VOID); +VOID APICCalibrateTimer(ULONG CPU); +VOID HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack); + +static __inline ULONG ThisCPU(VOID) +{ + return (APICRead(APIC_ID) & APIC_ID_MASK) >> 24; +} + + +#endif + + +/* EOF */ + diff --git a/reactos/hal/halppc/include/bus.h b/reactos/hal/halppc/include/bus.h new file mode 100644 index 00000000000..b231d5ecf22 --- /dev/null +++ b/reactos/hal/halppc/include/bus.h @@ -0,0 +1,133 @@ +/* + + */ + +#ifndef __INTERNAL_HAL_BUS_H +#define __INTERNAL_HAL_BUS_H + + +typedef NTSTATUS +(STDCALL *pAdjustResourceList)(IN PBUS_HANDLER BusHandler, + IN ULONG BusNumber, + IN OUT PCM_RESOURCE_LIST Resources); + +typedef NTSTATUS +(STDCALL *pAssignSlotResources)(IN PBUS_HANDLER BusHandler, + IN ULONG BusNumber, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources); + +typedef ULONG +(STDCALL *pGetSetBusData)(IN PBUS_HANDLER BusHandler, + IN ULONG BusNumber, + IN ULONG SlotNumber, + OUT PVOID Buffer, + IN ULONG Offset, + IN ULONG Length); + +typedef ULONG +(STDCALL *pGetInterruptVector)(IN PBUS_HANDLER BusHandler, + IN ULONG BusNumber, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity); + +typedef ULONG +(STDCALL *pTranslateBusAddress)(IN PBUS_HANDLER BusHandler, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress); + +typedef struct _BUS_HANDLER +{ + LIST_ENTRY Entry; + INTERFACE_TYPE InterfaceType; + BUS_DATA_TYPE BusDataType; + ULONG BusNumber; + ULONG RefCount; + + pGetSetBusData GetBusData; + pGetSetBusData SetBusData; + pAdjustResourceList AdjustResourceList; + pAssignSlotResources AssignSlotResources; + pGetInterruptVector GetInterruptVector; + pTranslateBusAddress TranslateBusAddress; +} BUS_HANDLER; + + +/* FUNCTIONS *****************************************************************/ + +/* bus.c */ +PBUS_HANDLER +HalpAllocateBusHandler(INTERFACE_TYPE InterfaceType, + BUS_DATA_TYPE BusDataType, + ULONG BusNumber); + +/* sysbus.h */ +ULONG STDCALL +HalpGetSystemInterruptVector(PVOID BusHandler, + ULONG BusNumber, + ULONG BusInterruptLevel, + ULONG BusInterruptVector, + PKIRQL Irql, + PKAFFINITY Affinity); + +BOOLEAN STDCALL +HalpTranslateSystemBusAddress(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PHYSICAL_ADDRESS BusAddress, + PULONG AddressSpace, + PPHYSICAL_ADDRESS TranslatedAddress); + +/* isa.c */ +ULONG STDCALL +HalpGetIsaInterruptVector(PVOID BusHandler, + ULONG BusNumber, + ULONG BusInterruptLevel, + ULONG BusInterruptVector, + PKIRQL Irql, + PKAFFINITY Affinity); + +BOOLEAN STDCALL +HalpTranslateIsaBusAddress(PBUS_HANDLER BusHandler, + ULONG BusNumber, + PHYSICAL_ADDRESS BusAddress, + PULONG AddressSpace, + PPHYSICAL_ADDRESS TranslatedAddress); + +/* time.c */ +ULONG STDCALL +HalpGetCmosData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length); + +ULONG STDCALL +HalpSetCmosData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length); + +/* mca.h */ +ULONG STDCALL +HalpGetMicroChannelData(PBUS_HANDLER BusHandler, + ULONG BusNumber, + ULONG SlotNumber, + PVOID Buffer, + ULONG Offset, + ULONG Length); + +#endif /* __INTERNAL_HAL_BUS_H */ + +/* EOF */ + diff --git a/reactos/hal/halppc/include/hal.h b/reactos/hal/halppc/include/hal.h new file mode 100644 index 00000000000..b15a4d9800d --- /dev/null +++ b/reactos/hal/halppc/include/hal.h @@ -0,0 +1,37 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Hardware Abstraction Layer + * FILE: hal/halx86/include/hal.h + * PURPOSE: HAL Header + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ******************************************************************/ + +/* C Headers */ +#include + +/* IFS/DDK/NDK Headers */ +#include +#include +#include +#include +#include +#include +#include + +#define KPCR_BASE 0xFF000000 // HACK! + +/* Internal HAL Headers */ +#include "apic.h" +#include "bus.h" +#include "halirq.h" +#include "haldma.h" +#include "halp.h" +#include "mps.h" +#include "ioapic.h" + +/* Helper Header */ +#include + +/* EOF */ diff --git a/reactos/hal/halppc/include/haldma.h b/reactos/hal/halppc/include/haldma.h new file mode 100644 index 00000000000..59ddb9338a0 --- /dev/null +++ b/reactos/hal/halppc/include/haldma.h @@ -0,0 +1,383 @@ +#ifndef HALDMA_H +#define HALDMA_H + +/* + * DMA Page Register Structure + * 080 DMA RESERVED + * 081 DMA Page Register (channel 2) + * 082 DMA Page Register (channel 3) + * 083 DMA Page Register (channel 1) + * 084 DMA RESERVED + * 085 DMA RESERVED + * 086 DMA RESERVED + * 087 DMA Page Register (channel 0) + * 088 DMA RESERVED + * 089 PS/2-DMA Page Register (channel 6) + * 08A PS/2-DMA Page Register (channel 7) + * 08B PS/2-DMA Page Register (channel 5) + * 08C PS/2-DMA RESERVED + * 08D PS/2-DMA RESERVED + * 08E PS/2-DMA RESERVED + * 08F PS/2-DMA Page Register (channel 4) + */ + +typedef struct _DMA_PAGE +{ + UCHAR Reserved1; + UCHAR Channel2; + UCHAR Channel3; + UCHAR Channel1; + UCHAR Reserved2[3]; + UCHAR Channel0; + UCHAR Reserved3; + UCHAR Channel6; + UCHAR Channel7; + UCHAR Channel5; + UCHAR Reserved4[3]; + UCHAR Channel4; +} DMA_PAGE, *PDMA_PAGE; + +/* + * DMA Channel Mask Register Structure + * + * MSB LSB + * x x x x x x x x + * ------------------- - ----- + * | | | 00 - Select channel 0 mask bit + * | | \---- 01 - Select channel 1 mask bit + * | | 10 - Select channel 2 mask bit + * | | 11 - Select channel 3 mask bit + * | | + * | \---------- 0 - Clear mask bit + * | 1 - Set mask bit + * | + * \----------------------- xx - Reserved + */ + +typedef struct _DMA_CHANNEL_MASK +{ + UCHAR Channel: 2; + UCHAR SetMask: 1; + UCHAR Reserved: 5; +} DMA_CHANNEL_MASK, *PDMA_CHANNEL_MASK; + +/* + * DMA Mask Register Structure + * + * MSB LSB + * x x x x x x x x + * \---/ - - ----- ----- + * | | | | | 00 - Channel 0 select + * | | | | \---- 01 - Channel 1 select + * | | | | 10 - Channel 2 select + * | | | | 11 - Channel 3 select + * | | | | + * | | | | 00 - Verify transfer + * | | | \------------ 01 - Write transfer + * | | | 10 - Read transfer + * | | | + * | | \-------------------- 0 - Autoinitialized + * | | 1 - Non-autoinitialized + * | | + * | \------------------------ 0 - Address increment select + * | + * | 00 - Demand mode + * \------------------------------ 01 - Single mode + * 10 - Block mode + * 11 - Cascade mode + */ + +typedef union _DMA_MODE +{ + struct + { + UCHAR Channel: 2; + UCHAR TransferType: 2; + UCHAR AutoInitialize: 1; + UCHAR AddressDecrement: 1; + UCHAR RequestMode: 2; + }; + UCHAR Byte; +} DMA_MODE, *PDMA_MODE; + +/* + * DMA Extended Mode Register Structure + * + * MSB LSB + * x x x x x x x x + * - - ----- ----- ----- + * | | | | | 00 - Channel 0 select + * | | | | \---- 01 - Channel 1 select + * | | | | 10 - Channel 2 select + * | | | | 11 - Channel 3 select + * | | | | + * | | | | 00 - 8-bit I/O, by bytes + * | | | \------------ 01 - 16-bit I/O, by words, address shifted + * | | | 10 - 32-bit I/O, by bytes + * | | | 11 - 16-bit I/O, by bytes + * | | | + * | | \---------------------- 00 - Compatible + * | | 01 - Type A + * | | 10 - Type B + * | | 11 - Burst + * | | + * | \---------------------------- 0 - Terminal Count is Output + * | + * \---------------------------------0 - Disable Stop Register + * 1 - Enable Stop Register + */ + +typedef union _DMA_EXTENDED_MODE +{ + struct + { + UCHAR ChannelNumber: 2; + UCHAR TransferSize: 2; + UCHAR TimingMode: 2; + UCHAR TerminalCountIsOutput: 1; + UCHAR EnableStopRegister: 1; + }; + UCHAR Byte; +} DMA_EXTENDED_MODE, *PDMA_EXTENDED_MODE; + +/* DMA Extended Mode Register Transfer Sizes */ +#define B_8BITS 0 +#define W_16BITS 1 +#define B_32BITS 2 +#define B_16BITS 3 + +/* DMA Extended Mode Register Timing */ +#define COMPATIBLE_TIMING 0 +#define TYPE_A_TIMING 1 +#define TYPE_B_TIMING 2 +#define BURST_TIMING 3 + +/* Channel Stop Registers for each Channel */ +typedef struct _DMA_CHANNEL_STOP +{ + UCHAR ChannelLow; + UCHAR ChannelMid; + UCHAR ChannelHigh; + UCHAR Reserved; +} DMA_CHANNEL_STOP, *PDMA_CHANNEL_STOP; + +/* Transfer Types */ +#define VERIFY_TRANSFER 0x00 +#define READ_TRANSFER 0x01 +#define WRITE_TRANSFER 0x02 + +/* Request Modes */ +#define DEMAND_REQUEST_MODE 0x00 +#define SINGLE_REQUEST_MODE 0x01 +#define BLOCK_REQUEST_MODE 0x02 +#define CASCADE_REQUEST_MODE 0x03 + +#define DMA_SETMASK 4 +#define DMA_CLEARMASK 0 +#define DMA_READ 4 +#define DMA_WRITE 8 +#define DMA_SINGLE_TRANSFER 0x40 +#define DMA_AUTO_INIT 0x10 + +typedef struct _DMA1_ADDRESS_COUNT +{ + UCHAR DmaBaseAddress; + UCHAR DmaBaseCount; +} DMA1_ADDRESS_COUNT, *PDMA1_ADDRESS_COUNT; + +typedef struct _DMA2_ADDRESS_COUNT +{ + UCHAR DmaBaseAddress; + UCHAR Reserved1; + UCHAR DmaBaseCount; + UCHAR Reserved2; +} DMA2_ADDRESS_COUNT, *PDMA2_ADDRESS_COUNT; + +typedef struct _DMA1_CONTROL +{ + DMA1_ADDRESS_COUNT DmaAddressCount[4]; + UCHAR DmaStatus; + UCHAR DmaRequest; + UCHAR SingleMask; + UCHAR Mode; + UCHAR ClearBytePointer; + UCHAR MasterClear; + UCHAR ClearMask; + UCHAR AllMask; +} DMA1_CONTROL, *PDMA1_CONTROL; + +typedef struct _DMA2_CONTROL +{ + DMA2_ADDRESS_COUNT DmaAddressCount[4]; + UCHAR DmaStatus; + UCHAR Reserved1; + UCHAR DmaRequest; + UCHAR Reserved2; + UCHAR SingleMask; + UCHAR Reserved3; + UCHAR Mode; + UCHAR Reserved4; + UCHAR ClearBytePointer; + UCHAR Reserved5; + UCHAR MasterClear; + UCHAR Reserved6; + UCHAR ClearMask; + UCHAR Reserved7; + UCHAR AllMask; + UCHAR Reserved8; +} DMA2_CONTROL, *PDMA2_CONTROL; + +/* This structure defines the I/O Map of the 82537 controller. */ +typedef struct _EISA_CONTROL +{ + /* DMA Controller 1 */ + DMA1_CONTROL DmaController1; /* 00h-0Fh */ + UCHAR Reserved1[16]; /* 0Fh-1Fh */ + + /* Interrupt Controller 1 (PIC) */ + UCHAR Pic1Operation; /* 20h */ + UCHAR Pic1Interrupt; /* 21h */ + UCHAR Reserved2[30]; /* 22h-3Fh */ + + /* Timer */ + UCHAR TimerCounter; /* 40h */ + UCHAR TimerMemoryRefresh; /* 41h */ + UCHAR Speaker; /* 42h */ + UCHAR TimerOperation; /* 43h */ + UCHAR TimerMisc; /* 44h */ + UCHAR Reserved3[2]; /* 45-46h */ + UCHAR TimerCounterControl; /* 47h */ + UCHAR TimerFailSafeCounter; /* 48h */ + UCHAR Reserved4; /* 49h */ + UCHAR TimerCounter2; /* 4Ah */ + UCHAR TimerOperation2; /* 4Bh */ + UCHAR Reserved5[20]; /* 4Ch-5Fh */ + + /* NMI / Keyboard / RTC */ + UCHAR Keyboard; /* 60h */ + UCHAR NmiStatus; /* 61h */ + UCHAR Reserved6[14]; /* 62h-6Fh */ + UCHAR NmiEnable; /* 70h */ + UCHAR Reserved7[15]; /* 71h-7Fh */ + + /* DMA Page Registers Controller 1 */ + DMA_PAGE DmaController1Pages; /* 80h-8Fh */ + UCHAR Reserved8[16]; /* 90h-9Fh */ + + /* Interrupt Controller 2 (PIC) */ + UCHAR Pic2Operation; /* 0A0h */ + UCHAR Pic2Interrupt; /* 0A1h */ + UCHAR Reserved9[30]; /* 0A2h-0BFh */ + + /* DMA Controller 2 */ + DMA1_CONTROL DmaController2; /* 0C0h-0CFh */ + + /* System Reserved Ports */ + UCHAR SystemReserved[816]; /* 0D0h-3FFh */ + + /* Extended DMA Registers, Controller 1 */ + UCHAR DmaHighByteCount1[8]; /* 400h-407h */ + UCHAR Reserved10[2]; /* 408h-409h */ + UCHAR DmaChainMode1; /* 40Ah */ + UCHAR DmaExtendedMode1; /* 40Bh */ + UCHAR DmaBufferControl; /* 40Ch */ + UCHAR Reserved11[84]; /* 40Dh-460h */ + UCHAR ExtendedNmiControl; /* 461h */ + UCHAR NmiCommand; /* 462h */ + UCHAR Reserved12; /* 463h */ + UCHAR BusMaster; /* 464h */ + UCHAR Reserved13[27]; /* 465h-47Fh */ + + /* DMA Page Registers Controller 2 */ + DMA_PAGE DmaController2Pages; /* 480h-48Fh */ + UCHAR Reserved14[48]; /* 490h-4BFh */ + + /* Extended DMA Registers, Controller 2 */ + UCHAR DmaHighByteCount2[16]; /* 4C0h-4CFh */ + + /* Edge/Level Control Registers */ + UCHAR Pic1EdgeLevel; /* 4D0h */ + UCHAR Pic2EdgeLevel; /* 4D1h */ + UCHAR Reserved15[2]; /* 4D2h-4D3h */ + + /* Extended DMA Registers, Controller 2 */ + UCHAR DmaChainMode2; /* 4D4h */ + UCHAR Reserved16; /* 4D5h */ + UCHAR DmaExtendedMode2; /* 4D6h */ + UCHAR Reserved17[9]; /* 4D7h-4DFh */ + + /* DMA Stop Registers */ + DMA_CHANNEL_STOP DmaChannelStop[8]; /* 4E0h-4FFh */ +} EISA_CONTROL, *PEISA_CONTROL; + +typedef struct _ROS_MAP_REGISTER_ENTRY +{ + PVOID VirtualAddress; + PHYSICAL_ADDRESS PhysicalAddress; + ULONG Counter; +} ROS_MAP_REGISTER_ENTRY, *PROS_MAP_REGISTER_ENTRY; + +struct _ADAPTER_OBJECT { + /* + * New style DMA object definition. The fact that it is at the beginning + * of the ADAPTER_OBJECT structure allows us to easily implement the + * fallback implementation of IoGetDmaAdapter. + */ + DMA_ADAPTER DmaHeader; + + /* + * For normal adapter objects pointer to master adapter that takes care + * of channel allocation. For master adapter set to NULL. + */ + struct _ADAPTER_OBJECT *MasterAdapter; + + ULONG MapRegistersPerChannel; + PVOID AdapterBaseVa; + PROS_MAP_REGISTER_ENTRY MapRegisterBase; + + ULONG NumberOfMapRegisters; + ULONG CommittedMapRegisters; + + PWAIT_CONTEXT_BLOCK CurrentWcb; + KDEVICE_QUEUE ChannelWaitQueue; + PKDEVICE_QUEUE RegisterWaitQueue; + LIST_ENTRY AdapterQueue; + KSPIN_LOCK SpinLock; + PRTL_BITMAP MapRegisters; + PUCHAR PagePort; + UCHAR ChannelNumber; + UCHAR AdapterNumber; + USHORT DmaPortAddress; + DMA_MODE AdapterMode; + BOOLEAN NeedsMapRegisters; + BOOLEAN MasterDevice; + BOOLEAN Width16Bits; + BOOLEAN ScatterGather; + BOOLEAN IgnoreCount; + BOOLEAN Dma32BitAddresses; + BOOLEAN Dma64BitAddresses; + LIST_ENTRY AdapterList; +} ADAPTER_OBJECT; + +typedef struct _GROW_WORK_ITEM { + WORK_QUEUE_ITEM WorkQueueItem; + PADAPTER_OBJECT AdapterObject; + ULONG NumberOfMapRegisters; +} GROW_WORK_ITEM, *PGROW_WORK_ITEM; + +#define MAP_BASE_SW_SG 1 + +PADAPTER_OBJECT STDCALL +HalpDmaAllocateMasterAdapter(VOID); + +PDMA_ADAPTER STDCALL +HalpGetDmaAdapter( + IN PVOID Context, + IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters); + +ULONG STDCALL +HalpDmaGetDmaAlignment( + PADAPTER_OBJECT AdapterObject); + +#endif /* HALDMA_H */ diff --git a/reactos/hal/halppc/include/halirq.h b/reactos/hal/halppc/include/halirq.h new file mode 100644 index 00000000000..6d072738f5f --- /dev/null +++ b/reactos/hal/halppc/include/halirq.h @@ -0,0 +1,35 @@ +/* + * $Id: halirq.h 23907 2006-09-04 05:52:23Z arty $ + */ + +#ifndef __INCLUDE_HAL_HALIRQ +#define __INCLUDE_HAL_HALIRQ + +#ifdef CONFIG_SMP + +#define FIRST_DEVICE_VECTOR (0x30) +#define FIRST_SYSTEM_VECTOR (0xef) + +#define IRQ_BASE FIRST_DEVICE_VECTOR +#define NR_IRQS (FIRST_SYSTEM_VECTOR - FIRST_DEVICE_VECTOR) + +/* + * FIXME: + * This does not work if we have more than 24 IRQs (ie. more than one I/O APIC) + */ +#define VECTOR2IRQ(vector) (23 - (vector - IRQ_BASE) / 8) +#define VECTOR2IRQL(vector) (PROFILE_LEVEL - VECTOR2IRQ(vector)) +#define IRQ2VECTOR(irq) (((23 - (irq)) * 8) + FIRST_DEVICE_VECTOR) + +#else + +#define IRQ_BASE (0x30) +#define NR_IRQS (16) + +#define VECTOR2IRQ(vector) ((vector) - IRQ_BASE) +#define VECTOR2IRQL(vector) (PROFILE_LEVEL - VECTOR2IRQ(vector)) +#define IRQ2VECTOR(irq) ((irq) + IRQ_BASE) + +#endif + +#endif /* __INCLUDE_HAL_HALIRQ */ diff --git a/reactos/hal/halppc/include/halp.h b/reactos/hal/halppc/include/halp.h new file mode 100644 index 00000000000..88f607e699d --- /dev/null +++ b/reactos/hal/halppc/include/halp.h @@ -0,0 +1,97 @@ +/* + * + */ + +#ifndef __INTERNAL_HAL_HAL_H +#define __INTERNAL_HAL_HAL_H + +#define HAL_APC_REQUEST 0 +#define HAL_DPC_REQUEST 1 + +// +// Kernel Debugger Port Definition +// +typedef struct _KD_PORT_INFORMATION +{ + ULONG ComPort; + ULONG BaudRate; + ULONG BaseAddress; +} KD_PORT_INFORMATION, *PKD_PORT_INFORMATION; + +/* display.c */ +VOID FASTCALL HalInitializeDisplay (struct _ROS_LOADER_PARAMETER_BLOCK *LoaderBlock); +VOID FASTCALL HalClearDisplay (UCHAR CharAttribute); + +/* adapter.c */ +PADAPTER_OBJECT STDCALL HalpAllocateAdapterEx(ULONG NumberOfMapRegisters,BOOLEAN IsMaster, BOOLEAN Dma32BitAddresses); + +/* bus.c */ +VOID HalpInitBusHandlers (VOID); + +/* irql.c */ +VOID NTAPI HalpInitPICs(VOID); + +/* udelay.c */ +VOID HalpCalibrateStallExecution(VOID); + +/* pci.c */ +VOID HalpInitPciBus (VOID); + +/* enum.c */ +VOID HalpStartEnumerator (VOID); + +/* dma.c */ +VOID HalpInitDma (VOID); + +/* mem.c */ +PVOID HalpMapPhysMemory(ULONG PhysAddr, ULONG Size); + +/* Non-generic initialization */ +VOID HalpInitPhase0 (PROS_LOADER_PARAMETER_BLOCK LoaderBlock); +VOID HalpInitPhase1(VOID); +VOID NTAPI HalpClockInterrupt(VOID); + +/* sysinfo.c */ +NTSTATUS STDCALL +HalpQuerySystemInformation(IN HAL_QUERY_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN OUT PVOID Buffer, + OUT PULONG ReturnedLength); + +/* Non-standard functions */ +VOID STDCALL +HalReleaseDisplayOwnership(); + +BOOLEAN STDCALL +HalQueryDisplayOwnership(); + +#if defined(__GNUC__) +#define Ki386SaveFlags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) +#define Ki386RestoreFlags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") +#define Ki386DisableInterrupts() __asm__ __volatile__("cli\n\t") +#define Ki386EnableInterrupts() __asm__ __volatile__("sti\n\t") +#define Ki386HaltProcessor() __asm__ __volatile__("hlt\n\t") +#define Ki386RdTSC(x) __asm__ __volatile__("rdtsc\n\t" : "=A" (x.u.LowPart), "=d" (x.u.HighPart)) +#define Ki386Rdmsr(msr,val1,val2) __asm__ __volatile__("rdmsr" : "=a" (val1), "=d" (val2) : "c" (msr)) +#define Ki386Wrmsr(msr,val1,val2) __asm__ __volatile__("wrmsr" : /* no outputs */ : "c" (msr), "a" (val1), "d" (val2)) +#define Ki386ReadFsByte(offset,x) __asm__ __volatile__("movb %%fs:%c1,%0" : "=q" (x) : "i" (offset)) +#define Ki386WriteFsByte(offset,x) __asm__ __volatile__("movb %0,%%fs:%c1" : : "q" ((UCHAR)x), "i" (offset)) + +#elif defined(_MSC_VER) +#define Ki386SaveFlags(x) __asm pushfd __asm pop x; +#define Ki386RestoreFlags(x) __asm push x __asm popfd; +#define Ki386DisableInterrupts() __asm cli +#define Ki386EnableInterrupts() __asm sti +#define Ki386HaltProcessor() __asm hlt +#else +#error Unknown compiler for inline assembler +#endif + +typedef struct tagHALP_HOOKS +{ + void (*InitPciBus)(ULONG BusNumber, PBUS_HANDLER BusHandler); +} HALP_HOOKS, *PHALP_HOOKS; + +extern HALP_HOOKS HalpHooks; + +#endif /* __INTERNAL_HAL_HAL_H */ diff --git a/reactos/hal/halppc/include/ioapic.h b/reactos/hal/halppc/include/ioapic.h new file mode 100644 index 00000000000..114853c4a6d --- /dev/null +++ b/reactos/hal/halppc/include/ioapic.h @@ -0,0 +1,103 @@ +/* + * + */ + +#ifndef __INTERNAL_HAL_IOAPIC_H +#define __INTERNAL_HAL_IOAPIC_H + +/* I/O APIC Register Address Map */ +#define IOAPIC_IOREGSEL 0x0000 /* I/O Register Select (index) (R/W) */ +#define IOAPIC_IOWIN 0x0010 /* I/O window (data) (R/W) */ + +#define IOAPIC_ID 0x0000 /* IO APIC ID (R/W) */ +#define IOAPIC_VER 0x0001 /* IO APIC Version (R) */ +#define IOAPIC_ARB 0x0002 /* IO APIC Arbitration ID (R) */ +#define IOAPIC_REDTBL 0x0010 /* Redirection Table (0-23 64-bit registers) (R/W) */ + +#define IOAPIC_ID_MASK (0xF << 24) +#define GET_IOAPIC_ID(x) (((x) & IOAPIC_ID_MASK) >> 24) +#define SET_IOAPIC_ID(x) ((x) << 24) + +#define IOAPIC_VER_MASK (0xFF) +#define GET_IOAPIC_VERSION(x) (((x) & IOAPIC_VER_MASK)) +#define IOAPIC_MRE_MASK (0xFF << 16) /* Maximum Redirection Entry */ +#define GET_IOAPIC_MRE(x) (((x) & IOAPIC_MRE_MASK) >> 16) + +#define IOAPIC_ARB_MASK (0xF << 24) +#define GET_IOAPIC_ARB(x) (((x) & IOAPIC_ARB_MASK) >> 24) + +#define IOAPIC_TBL_DELMOD (0x7 << 10) /* Delivery Mode (see APIC_DM_*) */ +#define IOAPIC_TBL_DM (0x1 << 11) /* Destination Mode */ +#define IOAPIC_TBL_DS (0x1 << 12) /* Delivery Status */ +#define IOAPIC_TBL_INTPOL (0x1 << 13) /* Interrupt Input Pin Polarity */ +#define IOAPIC_TBL_RIRR (0x1 << 14) /* Remote IRR */ +#define IOAPIC_TBL_TM (0x1 << 15) /* Trigger Mode */ +#define IOAPIC_TBL_IM (0x1 << 16) /* Interrupt Mask */ +#define IOAPIC_TBL_DF0 (0xF << 56) /* Destination Field (physical mode) */ +#define IOAPIC_TBL_DF1 (0xFF<< 56) /* Destination Field (logical mode) */ +#define IOAPIC_TBL_VECTOR (0xFF << 0) /* Vector (10h - FEh) */ + +#include +typedef struct _IOAPIC_ROUTE_ENTRY { + ULONG vector : 8, + delivery_mode : 3, /* 000: FIXED + * 001: lowest priority + * 111: ExtINT + */ + dest_mode : 1, /* 0: physical, 1: logical */ + delivery_status : 1, + polarity : 1, + irr : 1, + trigger : 1, /* 0: edge, 1: level */ + mask : 1, /* 0: enabled, 1: disabled */ + __reserved_2 : 15; + + union { + struct { + ULONG __reserved_1 : 24, + physical_dest : 4, + __reserved_2 : 4; + } physical; + struct { + ULONG __reserved_1 : 24, + logical_dest : 8; + } logical; + } dest; +} IOAPIC_ROUTE_ENTRY, *PIOAPIC_ROUTE_ENTRY; +#include + +typedef struct _IOAPIC_INFO +{ + ULONG ApicId; /* APIC ID */ + ULONG ApicVersion; /* APIC version */ + ULONG ApicAddress; /* APIC address */ + ULONG EntryCount; /* Number of redirection entries */ +} IOAPIC_INFO, *PIOAPIC_INFO; + +#define IOAPIC_DEFAULT_BASE 0xFEC00000 /* Default I/O APIC Base Register Address */ + +extern ULONG IRQCount; /* Number of IRQs */ +extern UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ +extern UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ +extern IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ +extern ULONG IOAPICCount; /* Number of I/O APICs in the system */ +extern ULONG APICMode; /* APIC mode at startup */ +extern MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ + +VOID IOAPICSetupIrqs(VOID); +VOID IOAPICEnable(VOID); +VOID IOAPICSetupIds(VOID); +VOID IOAPICMaskIrq(ULONG Irq); +VOID IOAPICUnmaskIrq(ULONG Irq); + +VOID HaliReconfigurePciInterrupts(VOID); + +/* For debugging */ +VOID IOAPICDump(VOID); + +#endif + + + +/* EOF */ + diff --git a/reactos/hal/halppc/include/mps.h b/reactos/hal/halppc/include/mps.h new file mode 100644 index 00000000000..83f9cfbe501 --- /dev/null +++ b/reactos/hal/halppc/include/mps.h @@ -0,0 +1,204 @@ +#ifndef __INCLUDE_HAL_MPS +#define __INCLUDE_HAL_MPS + +/* + * FIXME: This does not work if we have more than 24 IRQs (ie. more than one + * I/O APIC) + */ +#define IRQL2VECTOR(irql) (IRQ2VECTOR(PROFILE_LEVEL - (irql))) + +#define IRQL2TPR(irql) ((irql) >= IPI_LEVEL ? IPI_VECTOR : ((irql) >= PROFILE_LEVEL ? LOCAL_TIMER_VECTOR : ((irql) > DISPATCH_LEVEL ? IRQL2VECTOR(irql) : 0))) + +typedef struct _KIRQ_TRAPFRAME +{ + ULONG Magic; + ULONG Gs; + ULONG Fs; + ULONG Es; + ULONG Ds; + ULONG Eax; + ULONG Ecx; + ULONG Edx; + ULONG Ebx; + ULONG Esp; + ULONG Ebp; + ULONG Esi; + ULONG Edi; + ULONG Eip; + ULONG Cs; + ULONG Eflags; +} KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME; + +#if 0 +/* This values are defined in halirql.h */ +#define FIRST_DEVICE_VECTOR 0x30 +#define FIRST_SYSTEM_VECTOR 0xEF +#endif + +#define NUMBER_DEVICE_VECTORS (FIRST_SYSTEM_VECTOR - FIRST_DEVICE_VECTOR) + + +/* MP Floating Pointer Structure */ +#define MPF_SIGNATURE (('_' << 24) | ('P' << 16) | ('M' << 8) | '_') + +#include +typedef struct _MP_FLOATING_POINTER +{ + ULONG Signature; /* _MP_ */ + ULONG Address; /* Physical Address Pointer (0 means no configuration table exist) */ + UCHAR Length; /* Structure length in 16-byte paragraphs */ + UCHAR Specification; /* Specification revision */ + UCHAR Checksum; /* Checksum */ + UCHAR Feature1; /* MP System Configuration Type */ + UCHAR Feature2; /* Bit 7 set for IMCR|PIC */ + UCHAR Feature3; /* Unused (0) */ + UCHAR Feature4; /* Unused (0) */ + UCHAR Feature5; /* Unused (0) */ +} MP_FLOATING_POINTER, *PMP_FLOATING_POINTER; + + +#define FEATURE2_IMCRP 0x80 + +/* MP Configuration Table Header */ +#define MPC_SIGNATURE (('P' << 24) | ('M' << 16) | ('C' << 8) | 'P') + +typedef struct _MP_CONFIGURATION_TABLE +{ + ULONG Signature; /* PCMP */ + USHORT Length; /* Size of configuration table */ + CHAR Specification; /* Specification Revision */ + CHAR Checksum; /* Checksum */ + CHAR Oem[8]; /* OEM ID */ + CHAR ProductId[12]; /* Product ID */ + ULONG OemTable; /* 0 if not present */ + USHORT OemTableSize; /* 0 if not present */ + USHORT EntryCount; /* Number of entries */ + ULONG LocalAPICAddress; /* Local APIC address */ + USHORT ExtTableLength; /* Extended Table Length */ + UCHAR ExtTableChecksum; /* Extended Table Checksum */ + UCHAR Reserved; /* Reserved */ +} MP_CONFIGURATION_TABLE, *PMP_CONFIGURATION_TABLE; + +/* MP Configuration Table Entries */ +#define MPCTE_PROCESSOR 0 /* One entry per processor */ +#define MPCTE_BUS 1 /* One entry per bus */ +#define MPCTE_IOAPIC 2 /* One entry per I/O APIC */ +#define MPCTE_INTSRC 3 /* One entry per bus interrupt source */ +#define MPCTE_LINTSRC 4 /* One entry per system interrupt source */ + + +typedef struct _MP_CONFIGURATION_PROCESSOR +{ + UCHAR Type; /* 0 */ + UCHAR ApicId; /* Local APIC ID for the processor */ + UCHAR ApicVersion; /* Local APIC version */ + UCHAR CpuFlags; /* CPU flags */ + ULONG CpuSignature; /* CPU signature */ + ULONG FeatureFlags; /* CPUID feature value */ + ULONG Reserved[2]; /* Reserved (0) */ +} MP_CONFIGURATION_PROCESSOR, *PMP_CONFIGURATION_PROCESSOR; + + + +typedef struct _MP_CONFIGURATION_BUS +{ + UCHAR Type; /* 1 */ + UCHAR BusId; /* Bus ID */ + CHAR BusType[6]; /* Bus type */ +} MP_CONFIGURATION_BUS, *PMP_CONFIGURATION_BUS; + +#define MAX_BUS 32 + +#define MP_BUS_ISA 1 +#define MP_BUS_EISA 2 +#define MP_BUS_PCI 3 +#define MP_BUS_MCA 4 + +#define BUSTYPE_EISA "EISA" +#define BUSTYPE_ISA "ISA" +#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ +#define BUSTYPE_MCA "MCA" +#define BUSTYPE_VL "VL" /* Local bus */ +#define BUSTYPE_PCI "PCI" +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_CBUS "CBUS" +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_MBI "MBI" +#define BUSTYPE_MBII "MBII" +#define BUSTYPE_MPI "MPI" +#define BUSTYPE_MPSA "MPSA" +#define BUSTYPE_NUBUS "NUBUS" +#define BUSTYPE_TC "TC" +#define BUSTYPE_VME "VME" +#define BUSTYPE_XPRESS "XPRESS" + + +typedef struct _MP_CONFIGURATION_IOAPIC +{ + UCHAR Type; /* 2 */ + UCHAR ApicId; /* I/O APIC ID */ + UCHAR ApicVersion; /* I/O APIC version */ + UCHAR ApicFlags; /* I/O APIC flags */ + ULONG ApicAddress; /* I/O APIC base address */ +} MP_CONFIGURATION_IOAPIC, *PMP_CONFIGURATION_IOAPIC; + +#define MAX_IOAPIC 2 + +#define MP_IOAPIC_USABLE 0x01 + + +typedef struct _MP_CONFIGURATION_INTSRC +{ + UCHAR Type; /* 3 */ + UCHAR IrqType; /* Interrupt type */ + USHORT IrqFlag; /* Interrupt flags */ + UCHAR SrcBusId; /* Source bus ID */ + UCHAR SrcBusIrq; /* Source bus interrupt */ + UCHAR DstApicId; /* Destination APIC ID */ + UCHAR DstApicInt; /* Destination interrupt */ +} MP_CONFIGURATION_INTSRC, *PMP_CONFIGURATION_INTSRC; + +#define MAX_IRQ_SOURCE 128 + +#define INT_VECTORED 0 +#define INT_NMI 1 +#define INT_SMI 2 +#define INT_EXTINT 3 + +#define IRQDIR_DEFAULT 0 +#define IRQDIR_HIGH 1 +#define IRQDIR_LOW 3 + + +typedef struct _MP_CONFIGURATION_INTLOCAL +{ + UCHAR Type; /* 4 */ + UCHAR IrqType; /* Interrupt type */ + USHORT IrqFlag; /* Interrupt flags */ + UCHAR SrcBusId; /* Source bus ID */ + UCHAR SrcBusIrq; /* Source bus interrupt */ + UCHAR DstApicId; /* Destination local APIC ID */ + UCHAR DstApicLInt; /* Destination local APIC interrupt */ +} MP_CONFIGURATION_INTLOCAL, *PMP_CONFIGURATION_INTLOCAL; +#include + +#define MP_APIC_ALL 0xFF + +#define CPU_FLAG_ENABLED 1 /* Processor is available */ +#define CPU_FLAG_BSP 2 /* Processor is the bootstrap processor */ + +#define CPU_STEPPING_MASK 0x0F +#define CPU_MODEL_MASK 0xF0 +#define CPU_FAMILY_MASK 0xF00 + +#define PIC_IRQS 16 + +/* Prototypes */ + +VOID HalpInitMPS(VOID); + + +#endif /* __INCLUDE_HAL_MPS */ + +/* EOF */ diff --git a/reactos/hal/halppc/up/halinit_up.c b/reactos/hal/halppc/up/halinit_up.c new file mode 100644 index 00000000000..38851c9dacf --- /dev/null +++ b/reactos/hal/halppc/up/halinit_up.c @@ -0,0 +1,35 @@ +/* $Id: halinit_up.c 23907 2006-09-04 05:52:23Z arty $ + * + * 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 + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS ***************************************************************/ + +VOID +HalpInitPhase0(PROS_LOADER_PARAMETER_BLOCK LoaderBlock) +{ + HalpInitPICs(); + + /* Setup busy waiting */ + HalpCalibrateStallExecution(); +} + +VOID +HalpInitPhase1(VOID) +{ + /* Nothing for now */ +} + +/* EOF */ diff --git a/reactos/hal/halppc/up/halup.rbuild b/reactos/hal/halppc/up/halup.rbuild new file mode 100644 index 00000000000..0ba1b0888a8 --- /dev/null +++ b/reactos/hal/halppc/up/halup.rbuild @@ -0,0 +1,12 @@ + + + + ../include + include + + + + halppc_generic + halinit_up.c + halup.rc + diff --git a/reactos/hal/halppc/up/halup.rc b/reactos/hal/halppc/up/halup.rc new file mode 100644 index 00000000000..90af6b929ff --- /dev/null +++ b/reactos/hal/halppc/up/halup.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "X86 Uniprocessor Hardware Abstraction Layer\0" +#define REACTOS_STR_INTERNAL_NAME "halup\0" +#define REACTOS_STR_ORIGINAL_FILENAME "halup.dll\0" +#include