mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
715 lines
17 KiB
715 lines
17 KiB
title "Software Interrupts"
|
|
;++
|
|
;
|
|
;Copyright (c) 1992, 1993, 1994 Corollary Inc
|
|
;
|
|
;Module Name:
|
|
;
|
|
; cbusapic.asm
|
|
;
|
|
;Abstract:
|
|
;
|
|
; This module implements the low-level Corollary Cbus HAL routines to deal
|
|
; with the Intel APIC distributed interrupt controller.
|
|
;
|
|
; This includes the_sending_ of software and IPI interrupts in Windows NT.
|
|
; The receipt of these interrupts is handled elsewhere.
|
|
;
|
|
; Note: The routines in this module are jmp'ed to directly from
|
|
; their common Hal counterparts.
|
|
;
|
|
;Author:
|
|
;
|
|
; Landy Wang ([email protected]) 26-Mar-1992
|
|
;
|
|
;Environment:
|
|
;
|
|
; Kernel Mode
|
|
;
|
|
;Revision History:
|
|
;
|
|
;--
|
|
|
|
|
|
.386p
|
|
.xlist
|
|
include hal386.inc
|
|
include callconv.inc ; calling convention macros
|
|
include i386\kimacro.inc
|
|
include cbus.inc
|
|
|
|
EXTRNP _CbusApicRedirectionInterrupt,0
|
|
|
|
;
|
|
; APIC register offsets...
|
|
;
|
|
APIC_IRR_OFFSET equ 0100h ; offset of APIC IRR registers
|
|
APIC_APC_IRR equ 0103h ; offset of APIC APC IRR register
|
|
APIC_DPC_IRR equ 0105h ; offset of APIC DPC IRR register
|
|
APIC_ICR_OFFSET equ 0300h ; offset of APIC intr cmd register
|
|
APIC_ICR_DEST_OFFSET equ 0310h ; offset of APIC intr cmd dest register
|
|
|
|
;
|
|
; APIC register bitfield definitions...
|
|
;
|
|
APIC_DEASSERT_RESET equ 000500h ; sending a DEASSERT-RESET command
|
|
APIC_LOGICAL_MODE equ 000800h ; sending an APIC-LOGICAL interrupt
|
|
APIC_ICR_BUSY equ 001000h ; APIC intr command reg is busy
|
|
APIC_TRIGGER_LEVEL equ 008000h ; generate a level interrupt
|
|
APIC_INTR_DISABLED equ 010000h ; disable this redirection entry
|
|
APIC_SELFINTR equ 040000h ; APIC's self-interrupt code
|
|
APIC_ALLINCLSELF equ 080000h ; sending a DEASSERT-RESET command
|
|
|
|
APIC_FULL_DRESET equ (APIC_ALLINCLSELF or APIC_TRIGGER_LEVEL or APIC_LOGICAL_MODE or APIC_DEASSERT_RESET)
|
|
|
|
;
|
|
; the IOAPIC_REGISTERS_T register access template...
|
|
;
|
|
RegisterSelect equ 0h ; this APIC's register select
|
|
WindowRegister equ 010h ; this APIC's window register
|
|
|
|
;
|
|
; left shift needed to convert processor_bit to Intel APIC ID - this applies
|
|
; to the logical destination ID and redirection entry registers only.
|
|
;
|
|
APIC_BIT_TO_ID equ 24 ; also in cbus1.h
|
|
|
|
;
|
|
; macro to wait for the delivery status register to become idle
|
|
;
|
|
APIC_WAIT macro apicreg
|
|
local a
|
|
|
|
align 4
|
|
a:
|
|
test dword ptr [apicreg + APIC_ICR_OFFSET], APIC_ICR_BUSY
|
|
jnz short a
|
|
|
|
endm
|
|
|
|
IOAPIC_READ macro ioapic, offset, answer
|
|
;
|
|
; 'ioapic' must point at the I/O APIC
|
|
; 'offset' is the offset to peek
|
|
; 'answer' is the peeked return value
|
|
;
|
|
mov dword ptr RegisterSelect[ioapic], offset
|
|
|
|
mov answer, dword ptr WindowRegister[ioapic]
|
|
endm
|
|
|
|
|
|
IOAPIC_WRITE macro ioapic, offset, value
|
|
;
|
|
; 'ioapic' must point at the I/O APIC
|
|
; 'offset' is the offset to poke
|
|
; 'value' is the value to poke
|
|
;
|
|
mov dword ptr RegisterSelect[ioapic], offset
|
|
|
|
mov dword ptr WindowRegister[ioapic], value
|
|
endm
|
|
|
|
.list
|
|
|
|
INIT SEGMENT DWORD PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; CbusApicArbsync ( VOID )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Broadcast an ALL-INCLUDING-SELF interrupt with deassert, reset &
|
|
; physical mode set. This routine is called after each APIC assigns
|
|
; itself a unique ID that can be used in APIC bus arbitration and
|
|
; priority arbitration. This syncs up the picture that each APIC
|
|
; has with the new ID that has just been added.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _CbusApicArbsync ,0
|
|
|
|
; get the base of APIC space, so we can then access
|
|
; the addr of hardware interrupt command register below
|
|
|
|
mov ecx, [_CbusLocalApic]
|
|
|
|
;
|
|
; disable interrupts so that polling the register and
|
|
; poking it becomes an atomic operation (for this processor),
|
|
; as specified in the Intel 82489DX specification.
|
|
; this is needed since interrupt service routines must
|
|
; be allowed to send IPIs (for example, DPCs, etc).
|
|
;
|
|
|
|
pushfd
|
|
cli
|
|
|
|
; wait for the delivery status register to become idle
|
|
|
|
APIC_WAIT ecx
|
|
|
|
;
|
|
; it is ILLEGAL to use the "destination shorthand" mode of the APIC
|
|
; for this command - we must set up the whole 64 bit register).
|
|
; both destination and vector are DONT_CARE for this request.
|
|
;
|
|
; no recipients (probably a don't care), but must be written
|
|
; _before_ the command is sent...
|
|
|
|
mov dword ptr [ecx + APIC_ICR_DEST_OFFSET], 0
|
|
|
|
;
|
|
; now we can send the full deassert-reset command
|
|
;
|
|
|
|
mov dword ptr [ecx + APIC_ICR_OFFSET], APIC_FULL_DRESET
|
|
|
|
popfd
|
|
|
|
stdRET _CbusApicArbsync
|
|
stdENDP _CbusApicArbsync
|
|
|
|
INIT ENDS
|
|
|
|
_TEXT SEGMENT DWORD PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; CbusRequestApicSoftwareInterrupt (
|
|
; IN KIRQL RequestIrql
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is used to issue a software interrupt to the
|
|
; calling processor. Since this is all done in hardware, the
|
|
; code to implement this is trivial. Our hardware supports
|
|
; sending the interrupt to lowest-in-group processors, which
|
|
; would be useful for a good number of DPCs, for example, but
|
|
; the kernel doesn't currently tell us which kinds of software
|
|
; interrupts need to go to the caller versus which can go to
|
|
; any processor.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (esp+4) = RequestIrql - Supplies the request IRQL value
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
;
|
|
; equates for accessing arguments
|
|
;
|
|
|
|
KsiRequestIrql equ byte ptr [esp+4]
|
|
;
|
|
|
|
cPublicProc _CbusRequestApicSoftwareInterrupt ,1
|
|
|
|
xor ecx, ecx ; faster than movzx
|
|
mov cl, KsiRequestIrql ; to get irql
|
|
|
|
;
|
|
; disable interrupts so that polling the register and
|
|
; poking it becomes an atomic operation (for this processor),
|
|
; as specified in the Intel 82489DX specification.
|
|
; this is needed since interrupt service routines must
|
|
; be allowed to send IPIs (for example, DPCs, etc).
|
|
;
|
|
|
|
pushfd
|
|
cli
|
|
|
|
;
|
|
; notice the CbusIrqlToVector[] indexing below -- it means
|
|
; that only pre-defined software interrupts can be sent,
|
|
; NOT any "int xx" command on demand.
|
|
;
|
|
mov eax, [_CbusIrqlToVector+4*ecx] ; get vector to issue
|
|
|
|
;
|
|
; if this function is ever changed so that we are
|
|
; allowed to interrupt a different processor than
|
|
; the caller, we will not be able to use the APIC
|
|
; shorthand method below to address them, and we will
|
|
; have to change the selfintr mode we use to issue.
|
|
; HalRequestApicIpi() already does these types of things, btw.
|
|
;
|
|
|
|
or eax, APIC_SELFINTR
|
|
|
|
; get the base of APIC space, so we can then access
|
|
; the addr of hardware interrupt command register below
|
|
|
|
mov ecx, [_CbusLocalApic]
|
|
|
|
; wait for the delivery status register to become idle
|
|
|
|
APIC_WAIT ecx
|
|
|
|
;
|
|
; since we are just interrupting ourself, we can use
|
|
; the "destination shorthand" mode of the APIC and
|
|
; just set up the single 32-bit write, instead of doing
|
|
; the whole 64 bit register). So,
|
|
;
|
|
; the APIC icr.destination = DONT_CARE
|
|
; the APIC icr.vector = IPI_TASKPRI
|
|
; the APIC icr.destination_shorthand = 01 (SELF);
|
|
;
|
|
|
|
mov [ecx + APIC_ICR_OFFSET], eax
|
|
|
|
;
|
|
; The interrupt must be pending before returning
|
|
; wait for the delivery status register to become idle.
|
|
; the delivery status register being idle just means that
|
|
; this local APIC has sent the interrupt message out on the
|
|
; APIC bus (it has to do this even for self interrupts!).
|
|
;
|
|
; but waiting for delivery status to be idle is NOT ENOUGH !!!
|
|
; you must also wait for the IRR bit to be set. this means
|
|
; this APIC's local unit has accepted the interrupt and the
|
|
; CPU has not yet sent the APIC an EOI.
|
|
;
|
|
|
|
APIC_WAIT ecx
|
|
|
|
popfd
|
|
|
|
stdRET _CbusRequestApicSoftwareInterrupt
|
|
|
|
stdENDP _CbusRequestApicSoftwareInterrupt
|
|
|
|
|
|
page ,132
|
|
subttl "CbusRequestApicIpi"
|
|
;++
|
|
;
|
|
; VOID
|
|
; CbusRequestApicIpi(
|
|
; IN ULONG Mask
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Requests an interprocessor interrupt
|
|
;
|
|
; for Windows NT, we use full distributed
|
|
; interrupt capability, and, thus, we will IGNORE the sswi address
|
|
; that RRD passes us and prioritize IPI as we see fit, given the
|
|
; other devices configured into the system.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; Mask - Mask of processors to be interrupted
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _CbusRequestApicIpi ,1
|
|
mov eax, [_CbusIpiVector]
|
|
|
|
mov edx, [esp+4] ; get requested recipients
|
|
|
|
;
|
|
; translate logical processor mask into the high byte of edx,
|
|
; since this is the only portion of the logical destination register
|
|
; that future APICs will use to compare with.
|
|
;
|
|
shl edx, APIC_BIT_TO_ID
|
|
|
|
; get the base of APIC space, so we can then access
|
|
; the addr of hardware interrupt command register below
|
|
|
|
mov ecx, [_CbusLocalApic]
|
|
|
|
;
|
|
; disable interrupts so that polling the register and
|
|
; poking it becomes an atomic operation (for this processor),
|
|
; as specified in the Intel 82489DX specification.
|
|
; this is needed since interrupt service routines must
|
|
; be allowed to send IPIs (for example, DPCs, etc).
|
|
;
|
|
|
|
pushfd
|
|
cli
|
|
|
|
; wait for the delivery status register to become idle
|
|
|
|
APIC_WAIT ecx
|
|
|
|
; use APIC logical mode to pop randomly-specified sets of processors
|
|
; we cannot use "destination shorthand" mode for this;
|
|
; we must write the whole 64 bit register. ie:
|
|
;
|
|
; The APIC icr.destination = processor_mask
|
|
; The APIC icr.vector = IPI_TASKPRI
|
|
; The APIC icr.destination_mode = 1 (LOGICAL);
|
|
;
|
|
; all other fields are zero.
|
|
;
|
|
; note that the high 32 bits of the interrupt command
|
|
; register must be written _BEFORE_ the low 32 bits.
|
|
;
|
|
|
|
; specify the CPUs...
|
|
mov [ecx + APIC_ICR_DEST_OFFSET], edx
|
|
|
|
; send the command...
|
|
or eax, APIC_LOGICAL_MODE ; set up mode & vector
|
|
mov dword ptr [ecx + APIC_ICR_OFFSET], eax
|
|
|
|
popfd
|
|
|
|
stdRET _CbusRequestApicIpi
|
|
stdENDP _CbusRequestApicIpi
|
|
|
|
|
|
;++
|
|
;
|
|
; ULONG
|
|
; READ_IOAPIC_ULONG(
|
|
; ULONG ApicNumber,
|
|
; PULONG Port
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Read the specified offset of the specified I/O APIC.
|
|
;
|
|
;
|
|
; Arguments:
|
|
; (esp+4) = Logical Apic Number
|
|
; (esp+8) = Port
|
|
;
|
|
; Returns:
|
|
; Value in Port.
|
|
;
|
|
;--
|
|
cPublicProc _READ_IOAPIC_ULONG ,2
|
|
|
|
mov ecx, [esp + 4] ; Apic number to access
|
|
mov eax, [_CbusIOApic+4*ecx] ; point at the I/O APIC
|
|
mov edx, [esp + 8] ; offset to peek
|
|
|
|
IOAPIC_READ eax, edx, eax
|
|
|
|
stdRET _READ_IOAPIC_ULONG
|
|
stdENDP _READ_IOAPIC_ULONG
|
|
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; WRITE_IOAPIC_ULONG(
|
|
; ULONG ApicNumber,
|
|
; PULONG Port,
|
|
; ULONG Value
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Write the specified offset with the specified value into
|
|
; the calling processor's I/O APIC.
|
|
;
|
|
; Arguments:
|
|
; (esp+4) = Logical Apic Number
|
|
; (esp+8) = Port
|
|
; (esp+c) = Value
|
|
;
|
|
;--
|
|
cPublicProc _WRITE_IOAPIC_ULONG ,3
|
|
|
|
mov ecx, [esp + 4] ; Apic number to access
|
|
mov eax, [_CbusIOApic+4*ecx] ; point at the I/O APIC
|
|
mov edx, [esp + 8] ; offset to poke
|
|
mov ecx, [esp + 0ch] ; value for the poke
|
|
|
|
IOAPIC_WRITE eax, edx, ecx
|
|
|
|
stdRET _WRITE_IOAPIC_ULONG
|
|
stdENDP _WRITE_IOAPIC_ULONG
|
|
|
|
|
|
page ,132
|
|
subttl "I/O APIC Update Interrupt"
|
|
;++
|
|
;
|
|
; VOID
|
|
; IOApicUpdate(
|
|
; VOID
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is the interrupt handler for an IPI interrupt generated
|
|
; at a priority just below that of normal IPIs. Its function is to
|
|
; poke the I/O APIC with the new masks that have been requested so
|
|
; that an interrupt can be accepted or ignored on a given processor.
|
|
;
|
|
; The priorities of this and CbusAllocateVector() have been carefully
|
|
; chosen so as to avoid deadlock.
|
|
;
|
|
; This routine is needed because each I/O APIC is only addressable from
|
|
; its local CPU.
|
|
;
|
|
; since this routine is entered directly via an interrupt gate, interrupt
|
|
; protection via cli is not necessary.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
ENTER_DR_ASSIST hiui_a, hiui_t
|
|
|
|
cPublicProc _IOApicUpdate ,0
|
|
|
|
;
|
|
; Save machine state on trap frame
|
|
;
|
|
|
|
ENTER_INTERRUPT hiui_a, hiui_t
|
|
|
|
; keep it simple, just issue the EOI right now.
|
|
; no changing of taskpri/irql is needed here.
|
|
; Thus, the EOI serves as the HalEndSystemInterrupt.
|
|
|
|
mov eax, _CbusRedirVector
|
|
CBUS_EOI eax, ecx ; destroy eax & ecx
|
|
|
|
stdCall _CbusApicRedirectionInterrupt
|
|
|
|
;
|
|
; Call this directly instead of through INTERRUPT_EXIT
|
|
; because the HalEndSystemInterrupt has already been done,
|
|
; and must only be done ONCE per interrupt.
|
|
;
|
|
|
|
cli
|
|
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
|
|
|
|
stdENDP _IOApicUpdate
|
|
|
|
|
|
page ,132
|
|
subttl "CbusApicRedirectionRequest"
|
|
;++
|
|
;
|
|
; VOID
|
|
; CbusApicRedirectionRequest(IN OUT PULONG spinaddress)
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Requests an interprocessor interrupt, at the HAL private CBUS1_REDIR_IPI
|
|
; priority. this must be higher than any device priority to prevent
|
|
; deadlocks. this routine always interrupts the processor that can
|
|
; access the I/O unit of the APIC distributing the interrupts amongst
|
|
; all the processors. we have currently wired that up to the boot
|
|
; processor for Cbus1.
|
|
;
|
|
; the boot processor will receive the interrupt in the IOApicUpdate()
|
|
; routine above.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; spinaddress - the caller will spin until the dword pointed to by
|
|
; this variable becomes zero. this insures that the
|
|
; processor controlling the APIC has actually satisfied
|
|
; our request.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _CbusApicRedirectionRequest ,1
|
|
|
|
;
|
|
; set the vector we're going to send
|
|
;
|
|
mov edx, [_CbusRedirVector]
|
|
|
|
; get the base of APIC space, so we can then access
|
|
; the addr of hardware interrupt command register below
|
|
|
|
mov ecx, [_CbusLocalApic]
|
|
|
|
; create the boot CPU ( 1 << 24) APIC ID in a portable manner...
|
|
|
|
mov eax, 1
|
|
shl eax, APIC_BIT_TO_ID
|
|
|
|
;
|
|
; disable interrupts so that polling the register and
|
|
; poking it becomes an atomic operation (for this processor),
|
|
; as specified in the Intel 82489DX specification.
|
|
; this is needed since interrupt service routines must
|
|
; be allowed to send IPIs (for example, DPCs, etc).
|
|
;
|
|
|
|
pushfd
|
|
cli
|
|
|
|
; wait for the delivery status register to become idle
|
|
|
|
APIC_WAIT ecx
|
|
|
|
; can't use "destination shorthand" mode for this -
|
|
; must write the whole 64 bit register. ie:
|
|
;
|
|
; The APIC icr.destination = processor_mask
|
|
; The APIC icr.vector = IPI_TASKPRI
|
|
; The APIC icr.destination_mode = 1 (LOGICAL);
|
|
;
|
|
; all other fields are zero.
|
|
;
|
|
; note that the destination word of the interrupt command
|
|
; register must be written _BEFORE_ the command word.
|
|
;
|
|
|
|
mov [ecx + APIC_ICR_DEST_OFFSET], eax
|
|
|
|
or edx, APIC_LOGICAL_MODE ; set up mode & vector
|
|
|
|
; send the command...
|
|
mov dword ptr [ecx + APIC_ICR_OFFSET], edx
|
|
|
|
; now wait for the processor controlling the APIC to finish our request
|
|
; do this in assembly so the compiler won't optimize this incorrectly
|
|
|
|
mov eax, [esp+8] ; remember we pushed flags
|
|
|
|
align 4
|
|
@@:
|
|
cmp dword ptr [eax], 0
|
|
jne @b
|
|
|
|
popfd
|
|
|
|
stdRET _CbusApicRedirectionRequest
|
|
stdENDP _CbusApicRedirectionRequest
|
|
|
|
page ,132
|
|
subttl "Cbus1RebootRequest"
|
|
;++
|
|
;
|
|
; VOID
|
|
; Cbus1RebootRequest(IN ULONG Processor);
|
|
;
|
|
; Routine Description:
|
|
;
|
|
;
|
|
; Arguments:
|
|
;
|
|
; Requests an interprocessor interrupt, at the HAL private CbusRebootVector.
|
|
; This interrupt is always sent to the non-boot processors.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _Cbus1RebootRequest ,1
|
|
mov edx, 1
|
|
mov ecx, [_CbusProcessors] ; set mask for all processors
|
|
shl edx, cl
|
|
sub edx, 1
|
|
|
|
mov eax, 1
|
|
mov ecx, [esp+8] ; get the requesting processor
|
|
shl eax, cl
|
|
not eax
|
|
and edx, eax
|
|
|
|
mov eax, [_CbusRebootVector]
|
|
|
|
cmp edx, 0 ; check for uniprocessor case
|
|
je no_ipi_needed
|
|
|
|
;
|
|
; translate logical processor mask into the high byte of edx,
|
|
; since this is the only portion of the logical destination register
|
|
; that future APICs will use to compare with.
|
|
;
|
|
shl edx, APIC_BIT_TO_ID
|
|
|
|
; get the base of APIC space, so we can then access
|
|
; the addr of hardware interrupt command register below
|
|
|
|
mov ecx, [_CbusLocalApic]
|
|
|
|
;
|
|
; disable interrupts so that polling the register and
|
|
; poking it becomes an atomic operation (for this processor),
|
|
; as specified in the Intel 82489DX specification.
|
|
; this is needed since interrupt service routines must
|
|
; be allowed to send IPIs (for example, DPCs, etc).
|
|
;
|
|
|
|
pushfd
|
|
cli
|
|
|
|
; wait for the delivery status register to become idle
|
|
|
|
APIC_WAIT ecx
|
|
|
|
; use APIC logical mode to pop randomly-specified sets of processors
|
|
; we cannot use "destination shorthand" mode for this;
|
|
; we must write the whole 64 bit register. ie:
|
|
;
|
|
; The APIC icr.destination = processor_mask
|
|
; The APIC icr.vector = IPI_TASKPRI
|
|
; The APIC icr.destination_mode = 1 (LOGICAL);
|
|
;
|
|
; all other fields are zero.
|
|
;
|
|
; note that the high 32 bits of the interrupt command
|
|
; register must be written _BEFORE_ the low 32 bits.
|
|
;
|
|
|
|
; specify the CPUs...
|
|
mov [ecx + APIC_ICR_DEST_OFFSET], edx
|
|
|
|
; send the command...
|
|
or eax, APIC_LOGICAL_MODE ; set up mode & vector
|
|
mov dword ptr [ecx + APIC_ICR_OFFSET], eax
|
|
|
|
popfd
|
|
|
|
no_ipi_needed:
|
|
|
|
stdRET _Cbus1RebootRequest
|
|
stdENDP _Cbus1RebootRequest
|
|
|
|
_TEXT ENDS
|
|
END
|