windows-nt/Source/XPSP1/NT/base/hals/halx86/i386/ixreboot.c
2020-09-26 16:20:57 +08:00

237 lines
4.7 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
ixreboot.c
Abstract:
Provides the interface to the firmware for x86. Since there is no
firmware to speak of on x86, this is just reboot support.
Author:
John Vert (jvert) 12-Aug-1991
Revision History:
--*/
//
// This module is compatible with PAE mode and therefore treats physical
// addresses as 64-bit entities.
//
#if !defined(_PHYS64_)
#define _PHYS64_
#endif
#include "halp.h"
#include "pci.h"
#ifdef ACPI_HAL
#include "acpitabl.h"
#include "xxacpi.h"
extern UCHAR HalpPiix4;
#endif
//
// Defines to let us diddle the CMOS clock and the keyboard
//
#define CMOS_CTRL (PUCHAR )0x70
#define CMOS_DATA (PUCHAR )0x71
#define RESET 0xfe
#define KEYBPORT (PUCHAR )0x64
//
// Private function prototypes
//
VOID
HalpReboot (
VOID
)
/*++
Routine Description:
This procedure resets the CMOS clock to the standard timer settings
so the bios will work, and then issues a reset command to the keyboard
to cause a warm boot.
It is very machine dependent, this implementation is intended for
PC-AT like machines.
This code copied from the "old debugger" sources.
N.B.
Will NOT return.
--*/
{
UCHAR Scratch;
PUSHORT Magic;
PUCHAR ResetAddress;
PHYSICAL_ADDRESS zeroPhysical;
PCI_SLOT_NUMBER slot;
//
// By sticking 0x1234 at physical location 0x472, we can bypass the
// memory check after a reboot.
//
zeroPhysical.QuadPart = 0;
Magic = HalpMapPhysicalMemory(zeroPhysical, 1);
if (Magic) {
Magic[0x472 / sizeof(USHORT)] = 0x1234;
}
//
// Turn off interrupts
//
HalpAcquireCmosSpinLock();
HalpDisableInterrupts();
//
// Reset the cmos clock to a standard value
// (We are setting the periodic interrupt control on the MC147818)
//
//
// Disable periodic interrupt
//
WRITE_PORT_UCHAR(CMOS_CTRL, 0x0b); // Set up for control reg B.
KeStallExecutionProcessor(1);
Scratch = READ_PORT_UCHAR(CMOS_DATA);
KeStallExecutionProcessor(1);
Scratch &= 0xbf; // Clear periodic interrupt enable
WRITE_PORT_UCHAR(CMOS_DATA, Scratch);
KeStallExecutionProcessor(1);
//
// Set "standard" divider rate
//
WRITE_PORT_UCHAR(CMOS_CTRL, 0x0a); // Set up for control reg A.
KeStallExecutionProcessor(1);
Scratch = READ_PORT_UCHAR(CMOS_DATA);
KeStallExecutionProcessor(1);
Scratch &= 0xf0; // Clear rate setting
Scratch |= 6; // Set default rate and divider
WRITE_PORT_UCHAR(CMOS_DATA, Scratch);
KeStallExecutionProcessor(1);
//
// Set a "neutral" cmos address to prevent weirdness
// (Why is this needed? Source this was copied from doesn't say)
//
WRITE_PORT_UCHAR(CMOS_CTRL, 0x15);
KeStallExecutionProcessor(1);
HalpResetAllProcessors();
#ifdef ACPI_HAL
if ((HalpFixedAcpiDescTable.Header.Revision > 1) &&
(HalpFixedAcpiDescTable.flags & RESET_CAP)) {
switch (HalpFixedAcpiDescTable.reset_reg.AddressSpaceID) {
case 0: // Memory
ResetAddress =
HalpMapPhysicalMemory(HalpFixedAcpiDescTable.reset_reg.Address, 1);
WRITE_REGISTER_UCHAR(ResetAddress,
HalpFixedAcpiDescTable.reset_val);
break;
case 1: // I/O
WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)HalpFixedAcpiDescTable.reset_reg.Address.LowPart,
HalpFixedAcpiDescTable.reset_val);
break;
case 2: // PCI Config
slot.u.AsULONG = 0;
slot.u.bits.DeviceNumber =
HalpFixedAcpiDescTable.reset_reg.Address.HighPart;
slot.u.bits.FunctionNumber =
HalpFixedAcpiDescTable.reset_reg.Address.LowPart >> 16;
HalSetBusDataByOffset(PCIBus,
0,
slot.u.AsULONG,
&HalpFixedAcpiDescTable.reset_val,
HalpFixedAcpiDescTable.reset_reg.Address.LowPart & 0xff,
1);
break;
}
}
#endif
//
// If we return, send the reset command to the keyboard controller
//
WRITE_PORT_UCHAR(KEYBPORT, RESET);
HalpHalt();
}
#ifndef ACPI_HAL
VOID
HaliHaltSystem (
VOID
)
/*++
Routine Description:
This procedure is called when the machine has crashed and is to be
halted
N.B.
Will NOT return.
--*/
{
_asm {
cli
hlt
}
}
VOID
HalpCheckPowerButton (
VOID
)
{
}
#endif