Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3523 lines
92 KiB

/*++
Copyright (c) 1992 Digital Equipment Corporation
Module Name:
jxioacc.s
Abstract:
This contains assembler code routines for the Alpha/Jensen machine.
The module contains the functions to turn quasi virtual
addresses into an Alpha superpage virtual address
and then read or write based on the request.
(We are using EV4 64-bit superpage mode.)
Author:
Rod Gamache [DEC] 19-May-1993
Jeff McLeman [DEC]
Joe Notarangelo [DEC]
Steve Jenness [DEC]
Completely rewrote all the ACCESS routines to use new design from
14-May-1993. Work was based largely on work originally done by
Jeff Mcleman on 15-Jul-1992. Format of new QVA is shown below.
Environment:
Executes in kernel mode.
Revision History:
--*/
#include "jnsndef.h"
#include "ksalpha.h"
#define BAD_QVA 0xBADABADA
#define BAD_LONG 1
#define BAD_WORD 2
#define SUPERVA 0xfffffc0000000000
#define SUPERVA_SHORT 0xfffffc0000000020
#define SUPERVA_LONG 0xfffffc0000000060
#define HAE_PHYSICAL_BASEL 0xd0000000
#define EISA_QUAD_OFFSET EISA_LONG_OFFSET*2 // To read next quadword
#define EISA_SECOND_LONG EISA_LONG_OFFSET + EISA_LONG_LEN
//
// Format of QVA:
//
// +----------------------------------------------+
// QVA: | 3 | 1 | 1 | 27 bit EISA offset |
// +----------------------------------------------+
// | | |
// v | v (upper 2 bits used as HAE index)
// KSEG1 | IO/
// v MEM
// EISA/
// COMBO
//
// if EISA/COMBO bit: 1 is EISA space; 0 is COMBO space
// if IO/MEM bit: 1 is IO space; 0 is MEMORY space
//
#define EISA_MEMORY -0x3fe0 // Used to generate EISA MEMORY address
#define EISA_IO -0x3fd0 // Used to generate EISA IO address
#define COMBO_IO -0x3ff0 // Used to generate COMBO IO address
#define IO_HI_SHIFT 28 // Used with preceeding masks to form
// upper bits of Superpage address
#define QVA_HAE_SHIFT 25 // Shift to get HAE selector bits
// Mask to get selector bits (KSEG1) after HAE shift
#define QVA_SELECTORS_SHIFTED 0x70
#define QVA_ENABLE_SHIFTED 0x50 // Mask to get QVA bits after HAE shift
#define EISA_BITS_ONEZERO 3*EISA_BYTE_OFFSET // mask for EISA address 1..0
// Mask to clear SELECTOR bits plus EISA/COMBO and IO/MEM bits, when
// used with LDAH this mask generates the QVA_CONTROL_FULL bit pattern plus
// bits <63:32> are 1's. We can then cleanly pick off bits <63:25>.
#define QVA_CONTROL -0x200
// Full mask to clear SELECTOR bits plus EISA/COMBO, IO/MEM bits, and HAE bits
#define QVA_CONTROL_FULL 0xfe000000
LEAF_ENTRY(READ_REGISTER_UCHAR)
/*++
Routine Description:
Reads a byte location in bus memory space. Since there are
no register buffers (RAM) in COMBO space on Jensen, we will
only support EISA access.
Arguments:
a0 QVA of byte to be read.
Return Value:
v0 Register data.
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get byte within longword
bne t1, 20f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We have already ignored the COMBO/EISA bit... we will now ignore
// the IO/MEM bit. This will save 2 instructions and we require that
// the REGISTER routines only be used for access to MEMORY space.
//
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
or t0, t2, t0 # generate superpage address
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 40f # br if HAE has to be set up
ldl v0, (t0) # get the longword
extbl v0, t3, v0 # get correct byte
ret zero, (ra)
20:
//
// On non-I/O space access, do a normal memory operation
//
ldq_u v0, (a0) # get entire quad,don't assume aligned
extbl v0, a0, v0 # get the byte
ret zero, (ra) # return
40:
//
// setup HAE.
//
// a0 = QVA
// t0 = superpage address for QVA
// t4 = HAE index
// t3 = byte within longword
// t2 = upper bits of EISA superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 90f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t5, (t1) # get original HAE value
bne t5, 90f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the byte from the EISA bus
//
ldl v0, (t0) # get the longword
extbl v0, t3, t4 # get correct byte
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL
//
SWAP_IRQL # restore original IRQL
bis t4, zero, v0 # put result in v0
ret zero, (ra)
#if DBG
90:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end READ_REGISTER_UCHAR
LEAF_ENTRY(READ_REGISTER_USHORT)
/*++
Routine Description:
Reads a byte location in bus memory space. Since there are
no register buffers (RAM) in COMBO space on Jensen, we will
only support EISA access. Note: a0 should be word aligned.
Arguments:
a0 QVA of word to be read.
Return Value:
v0 Register data.
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get word within longword
bne t1, 20f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index alone
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We have already ignored the COMBO/EISA bit... we will now ignore
// the IO/MEM bit. This will save 2 instructions and we require that
// the REGISTER routines only be used for access to MEMORY space.
//
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
or t0, t2, t0 # generate superpage address
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 40f # br if HAE has to be set up
ldl v0, EISA_WORD_LEN(t0) # get the word within longword
extwl v0, t3, v0 # get the correct word
ret zero, (ra)
20:
//
// On non-I/O space access, do a normal memory operation
//
ldq_u v0, (a0) # get entire quad,don't assume aligned
extwl v0, a0, v0 # get the word
ret zero, (ra) # return
40:
//
// setup HAE.
//
// a0 = QVA
// t0 = superpage address for QVA
// t4 = HAE index
// t3 = word within longword
// t2 = upper bits of superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 90f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t5, (t1) # get original HAE value
bne t5, 90f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the word from the EISA bus
//
ldl v0, EISA_WORD_LEN(t0) # get the word within longword
extwl v0, t3, t4 # get correct word
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL
//
SWAP_IRQL # restore original IRQL
bis t4, zero, v0 # put result in v0
ret zero, (ra)
#if DBG
90:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end READ_REGISTER_USHORT
LEAF_ENTRY(READ_REGISTER_ULONG)
/*++
Routine Description:
Reads a longword location in bus memory space. Since there are
no register buffers (RAM) in COMBO space on Jensen, we will
only support EISA access. Note: a0 should be longword aligned.
Arguments:
a0 QVA of longword to be read.
Return Value:
v0 Register data
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bne t1, 20f # br if not a bus address
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We have already ignored the COMBO/EISA bit... we will now ignore
// the IO/MEM bit. This will save 2 instructions and we require that
// the REGISTER routines only be used for access to MEMORY space.
//
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
or t0, t2, t0 # generate superpage address
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 40f # br if HAE has to be set up
ldl v0, EISA_LONG_LEN(t0) # read the longword
ret zero, (ra)
20:
//
// On non-I/O space access, do a normal memory operation
//
ldl v0, (a0) # read the longword
ret zero, (ra)
40:
//
// setup HAE.
//
// a0 = QVA
// t0 = superpage address for QVA
// t4 = HAE index
// t2 = upper bits of superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 90f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t5, (t1) # get original HAE value
bne t5, 90f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the longword from the EISA bus
//
ldl t4, EISA_LONG_LEN(t0) # read the longword
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL
//
SWAP_IRQL # restore original IRQL
bis t4, zero, v0 # put result in v0
ret zero, (ra)
#if DBG
90:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
//
// HAE has to be set up... this requires a lot of extra work!
//
ret zero, (ra)
.end READ_REGISTER_ULONG
LEAF_ENTRY(WRITE_REGISTER_UCHAR)
/*++
Routine Description:
Writes a byte location in bus memory space. Since there are no
register buffers (RAM) in COMBO space on Jensen, we will only
support access to EISA space.
Arguments:
a0 QVA of byte to be written.
a1 Byte Datum to be written.
Return Value:
v0 Register data.
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get byte within longword
bne t1, 20f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index alone
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We have already ignored the COMBO/EISA bit... we will now ignore
// the IO/MEM bit. This will save 2 instructions and we require that
// the REGISTER routines only be used for access to MEMORY space.
//
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
ldiq t2, EISA_MEMORY # form upper bits of PA
insbl a1, t3, t3 # put byte in correct position
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
or t0, t2, t0 # generate superpage address
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 40f # br if HAE has to be set up
stl t3, (t0) # write the byte
mb # order the write
ret zero, (ra)
20:
//
// If a non I/O space address, do normal memory operations
//
ldq_u t0, (a0) # get the quad
mskbl t0, a0, t0 # mask the proper byte
insbl a1, a0, t1 # put byte into position
bis t1, t0, t0 # merge byte in result
stq_u t0, (a0) # store the result
ret zero, (ra)
40:
//
// setup HAE.
//
// a0 = QVA
// t0 = superpage address for QVA
// t4 = HAE index
// t3 = data to be written (already put into correct lane position)
// t2 = upper bits of superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 90f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t5, (t1) # get original HAE value
bne t5, 90f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can write the byte to the EISA bus
//
stl t3, (t0) # put byte out on bus
//mb # order the writes, we rely on
# the fact that EV4 will not reorder
# writes, but only merge writes. The
# next mb below will handle our flush.
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
#if DBG
90:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end WRITE_REGISTER_UCHAR
LEAF_ENTRY(WRITE_REGISTER_USHORT)
/*++
Routine Description:
Writes a word location in bus memory space. Since there are no
register buffers (RAM) in COMBO space on Jensen, we will only
support access to EISA space. Note: a0 should be word aligned.
Arguments:
a0 QVA of word to be written.
a1 Word Datum to be written
Return Value:
v0 Register data.
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get byte within longword
bne t1, 20f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We have already ignored the COMBO/EISA bit... we will now ignore
// the IO/MEM bit. This will save 2 instructions and we require that
// the REGISTER routines only be used for access to MEMORY space.
//
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
ldiq t2, EISA_MEMORY # form upper bits of PA
inswl a1, t3, t3 # put the word into correct place
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
or t0, t2, t0 # generate superpage address
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 40f # br if HAE has to be set up
stl t3, EISA_WORD_LEN(t0) # write the word
mb # order the write
ret zero, (ra)
20:
//
// If a non I/O space address, do normal memory operations
//
ldq_u t0, (a0) # get the quad
mskwl t0, a0, t0 # mask the proper word
inswl a1, a0, t1 # put word into position
bis t0, t1, t0 # merge in result
stq_u t0, (a0) # store the result
ret zero, (ra)
40:
//
// setup HAE.
//
// a0 = QVA
// t0 = superpage address for QVA
// t4 = HAE index
// t3 = data to be written (already put into correct lane position)
// t2 = upper bits of superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 90f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t5, (t1) # get original HAE value
bne t5, 90f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can write the word to the EISA bus
//
stl t3, EISA_WORD_LEN(t0) # write the word
//mb # order the writes, we rely on
# the fact that EV4 will not reorder
# writes, but only merge writes. The
# next mb below will handle our flush.
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
#if DBG
90:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end WRITE_REGISTER_USHORT
LEAF_ENTRY(WRITE_REGISTER_ULONG)
/*++
Routine Description:
Writes a longword location in bus memory space. Since there are no
register buffers (RAM) in COMBO space on Jensen, we will only
support access to EISA space. Note: a0 should be longword aligned.
Arguments:
a0 QVA of longword to be written.
a1 Longword to be written.
Return Value:
v0 Register data
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bne t1, 20f # br if not a bus address
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We have already ignored the COMBO/EISA bit... we will now ignore
// the IO/MEM bit. This will save 2 instructions and we require that
// the REGISTER routines only be used for access to MEMORY space.
//
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
or t0, t2, t0 # generate superpage address
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 40f # br if HAE has to be set up
stl a1, EISA_LONG_LEN(t0) # write the longword
mb # order the write
ret zero, (ra)
20:
//
// On non-I/O space access, do a normal memory operation
//
stl a1, (a0) # store the longword
ret zero, (ra)
40:
//
// setup HAE.
//
// a0 = QVA
// a1 = data to be written
// t0 = superpage address for QVA
// t4 = HAE index
// t2 = upper bits of superpage address
//
bis a1, zero, t3 # move data to safe register
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 90f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t5, (t1) # get original HAE value
bne t5, 90f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can write the data to the EISA bus
//
stl t3, EISA_LONG_LEN(t0) # write the longword
//mb # order the writes, we rely on
# the fact that EV4 will not reorder
# writes, but only merge writes. The
# next mb below will handle our flush.
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
#if DBG
90:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end WRITE_REGISTER_ULONG
LEAF_ENTRY(READ_PORT_UCHAR)
/*++
Routine Description:
Reads a byte location in I/O space. Unlike the _REGISTER_ routines,
these routines do not support access to main memory. This routine
supports both EISA IO and COMBO space.
Arguments:
a0 QVA of byte to be read.
Return Value:
v0 Register data.
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
ldah t0, QVA_CONTROL(zero) # get mask clear bits
s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
bic a0, t0, t0 # clear QVA control bits a0<63:25>
bge t2, 20f # br if COMBO address
//
// EISA address
//
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
and a0, 3, t3 # get byte within longword
ldl v0, (t0) # get the longword
extbl v0, t3, v0 # get correct byte
ret zero, (ra)
20:
//
// COMBO address
//
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in COMBO IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, COMBO_IO # form upper bits of PA
sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
ldl v0, (t0) # get the longword
//
// Our C compiler expects returned UCHAR values to be zero-extended.
//
zapnot v0, 1, v0
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end READ_PORT_UCHAR
LEAF_ENTRY(READ_PORT_USHORT)
/*++
Routine Description:
Reads a word location from I/O space. Since during a triple boot,
and at other times, drivers may probe for the existence of PORTs on
any bus, we must support all modes of access, even though the COMBO
space does not have any SHORT PORTs. Note: a0 should be word aligned.
Arguments:
a0 QVA of word to be read.
Return Value:
v0 Register data.
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
ldah t0, QVA_CONTROL(zero) # get mask clear bits
s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
bic a0, t0, t0 # clear QVA control bits a0<63:25>
bge t2, 20f # br if COMBO address
//
// EISA address
//
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
and a0, 3, t3 # get byte within longword
ldl v0, EISA_WORD_LEN(t0) # get the word within longword
extwl v0, t3, v0 # get correct word
ret zero, (ra)
20:
//
// COMBO Address
//
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in COMBO IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, COMBO_IO # form upper bits of PA
sll t0, COMBO_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
ldl v0, (t0) # get the longword
//
// Our C compiler expects returned USHORT values to be zero-extended.
//
zapnot v0, 3, v0 # clear all but low 2 bytes
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end READ_PORT_USHORT
LEAF_ENTRY(READ_PORT_ULONG)
/*++
Routine Description:
Reads a longword location from I/O space. Since during a triple boot,
and at other times, drivers may probe for the existence of PORTs on
any bus, we must support all modes of access, even though the COMBO
space does not have any LONG PORTs. Note: a0 should be longword aligned.
Arguments:
a0 QVA of longword to be read.
Return Value:
v0 Register data
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
ldah t0, QVA_CONTROL(zero) # get mask clear bits
s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
bic a0, t0, t0 # clear QVA control bits a0<63:25>
bge t2, 20f # br if COMBO address - error
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
ldl v0, EISA_LONG_LEN(t0) # get the longword
ret zero, (ra)
20:
//
// COMBO Address
//
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in COMBO IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, COMBO_IO # form upper bits of PA
sll t0, COMBO_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
ldl v0, (t0) # get the longword
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end READ_PORT_ULONG
LEAF_ENTRY(WRITE_PORT_UCHAR)
/*++
Routine Description:
Writes a byte location in I/O space. Unlike the _REGISTER_ routines,
these routines do not support access to main memory. This routine
supports both EISA IO and COMBO space.
Arguments:
a0 QVA of byte to be written.
a1 Byte Datum to be written.
Return Value:
v0 Register data.
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
ldah t0, QVA_CONTROL(zero) # get mask clear bits
s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
bic a0, t0, t0 # clear QVA control bits a0<63:25>
bge t2, 20f # br if COMBO address
//
// EISA address
//
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
and a0, 3, t3 # get byte within longword
or t0, t4, t0 # generate superpage address
insbl a1, t3, t1 # put the byte in the correct position
stl t1, (t0) # write the byte
mb # order the writes
ret zero, (ra)
20:
//
// COMBO address
//
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in COMBO IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, COMBO_IO # form upper bits of PA
sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
stl a1, (t0) # write the byte
mb # order the writes
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end WRITE_PORT_UCHAR
LEAF_ENTRY(WRITE_PORT_USHORT)
/*++
Routine Description:
Writes a word location in I/O space. Since during a triple boot,
and at other times, drivers may probe for the existence of PORTs on
any bus, we must support all modes of access, even though the COMBO
space does not have any SHORT PORTs. Note: a0 should be word aligned.
Arguments:
a0 QVA of word to be written.
a1 Word Datum to be written
Return Value:
v0 Register data.
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
ldah t0, QVA_CONTROL(zero) # get mask clear bits
s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
bic a0, t0, t0 # clear QVA control bits a0<63:25>
bge t2, 20f # br if COMBO address - error
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
and a0, 3, t3 # get word within longword
or t0, t4, t0 # generate superpage address
inswl a1, t3, t1 # put the byte in the correct position
stl t1, EISA_WORD_LEN(t0) # write the word
mb # order the writes
ret zero, (ra)
20:
//
// COMBO address
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in COMBO IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, COMBO_IO # form upper bits of PA
sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
stl a1, (t0) # write the byte
mb # order the writes
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end WRITE_PORT_USHORT
LEAF_ENTRY(WRITE_PORT_ULONG)
/*++
Routine Description:
Writes a longword location in I/O space. Since during a triple boot
and at other times, drivers may probe for the existence of PORTs on
any bus, we must support all modes of access, even though the COMBO
space does not have any LONG PORTs. Note: a0 should be longword
aligned.
Arguments:
a0 QVA of longword to be written.
a1 Longword to be written.
Return Value:
v0 Register data
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
ldah t0, QVA_CONTROL(zero) # get mask clear bits
s8addl a0, zero, t2 # get COMBO/EISA bit in sign bit
bic a0, t0, t0 # clear QVA control bits a0<63:25>
bge t2, 20f # br if COMBO address - error
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
stl a1, EISA_LONG_LEN(t0) # write the longword
mb # order the writes
ret zero, (ra)
20:
//
// COMBO address
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in COMBO IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, COMBO_IO # form upper bits of PA
sll t0, COMBO_BIT_SHIFT, t0 # shift for combo
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
stl a1, (t0) # write the byte
mb # order the writes
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end WRITE_PORT_ULONG
LEAF_ENTRY(READ_PORT_BUFFER_UCHAR)
/*++
Routine Description:
Reads from the specified port buffer address. Since there are no
PORT buffers on Jensen, there is no code to handle COMBO space in
this routine.
Arguments:
a0 QVA of source port.
a1 VA of destination buffer in memory.
a2 Number of bytes to move (Count).
Return Value:
None
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
beq a2, 30f # leave now if nothing to move
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
and a0, 3, t3 # get byte within longword
20:
ldl v0, (t0) # get the longword
subl a2, 1, a2 # decrement count
extbl v0, t3, v0 # get the correct byte
stb v0, (a1) # cheat and let the assembler do it
addl a1, 1, a1 # next byte in buffer
bne a2, 20b # loop if more bytes to move
30:
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end READ_PORT_BUFFER_UCHAR
LEAF_ENTRY(READ_PORT_BUFFER_USHORT)
/*++
Routine Description:
Reads from the specified port buffer address. Since there are no
PORT buffers on Jensen, there is no code to handle COMBO space in
this routine. Note: a0, a1 should be word aligned.
Arguments:
a0 QVA of source port.
a1 VA of destination buffer in memory.
a2 Number of words to move (Count).
Return Value:
None
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
beq a2, 30f # leave now if nothing to move
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
and a0, 3, t3 # get word within longword
20:
ldl v0, EISA_WORD_LEN(t0) # get the word within the longword
subl a2, 1, a2 # decrement count
extwl v0, t3, v0 # get the correct word
stw v0, (a1) # cheat and let the assembler do it
addl a1, 2, a1 # next word in buffer
bne a2, 20b # loop if more bytes to move
30:
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end READ_PORT_BUFFER_USHORT
LEAF_ENTRY(READ_PORT_BUFFER_ULONG)
/*++
Routine Description:
Reads from the specified port buffer address. Since there are no
PORT buffers on Jensen, there is no code to handle COMBO space in
this routine. Note: a0, a1 should be longword aligned.
Arguments:
a0 QVA of source port.
a1 VA of destination buffer in memory.
a2 Number of longs to move (Count).
Return Value:
None
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
beq a2, 30f # leave now if nothing to move
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
20:
ldl v0, EISA_LONG_LEN(t0) # get the longword
subl a2, 1, a2 # decrement count
stl v0, (a1) # save the longword
addl a1, 4, a1 # next byte in buffer
bne a2, 20b # loop if more bytes to move
30:
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end READ_PORT_BUFFER_ULONG
LEAF_ENTRY(WRITE_PORT_BUFFER_UCHAR)
/*++
Routine Description:
Writes to the specified port buffer address. Since there are no
PORT buffers on Jensen, there is no code to handle COMBO space in
this routine.
Arguments:
a0 QVA of destination port.
a1 VA of source buffer in memory.
a2 Number of bytes to move (Count).
Return Value:
None
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
beq a2, 30f # leave now if nothing to move
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
and a0, 3, t3 # get byte within longword
20:
ldq_u t1, 0(a1) # get quad surrounding byte
subl a2, 1, a2 # decrement count
extbl t1, a1, t1 # extract appropriate byte
addl a1, 1, a1 # increment buffer pointer
insbl t1, t3, t1 # put byte to appropriate lane
stl t1, 0(t0) # store to port
mb # push writes off chip
bne a2, 20b # loop if more bytes to move
30:
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end WRITE_PORT_BUFFER_UCHAR
LEAF_ENTRY(WRITE_PORT_BUFFER_USHORT)
/*++
Routine Description:
Writes to the specified port buffer address. Since there are no
PORT buffers on Jensen, there is no code to handle COMBO space in
this routine. Note: a0, a1 should be word aligned.
Arguments:
a0 QVA of destination port.
a1 VA of source buffer in memory.
a2 Number of words to move (Count).
Return Value:
None
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
beq a2, 30f # leave now if nothing to move
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
and a0, 3, t3 # get byte within longword
20:
ldq_u t1, (a1) # get quad surrounding word
subl a2, 1, a2 # decrement count
extwl t1, a1, t1 # extract appropriate word
addl a1, 2, a1 # increment buffer pointer
inswl t1, t3, t1 # put word to appropriate lane
stl t1, EISA_WORD_LEN(t0) # store the word to the port
mb # push writes off chip
bne a2, 20b # loop if more bytes to move
30:
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end WRITE_PORT_BUFFER_USHORT
LEAF_ENTRY(WRITE_PORT_BUFFER_ULONG)
/*++
Routine Description:
Writes to the specified port buffer address. Since there are no
PORT buffers on Jensen, there is no code to handle COMBO space in
this routine. Note: a0, a1 should be longword aligned.
Arguments:
a0 QVA of destination port.
a1 VA of source buffer in memory.
a2 Number of longs to move (Count).
Return Value:
None
--*/
#if DBG
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address - error
and t2, 3, t4 # get HAE index
//
// Check if HAE is non-zero. For IO space access this should never
// be non-zero!
//
bne t4, 40f # br if HAE non-zero - error
#endif
beq a2, 30f # leave now if nothing to move
ldah t0, QVA_CONTROL(zero) # get mask clear bits
bic a0, t0, t0 # clear QVA control bits a0<63:25>
//
// Note - at this point we know bits t0<63:25> = 0
//
// We will now ignore the IO/MEM bit and generate bits PA<63:32>
// knowing that we are in EISA IO space. This will save 2 instructions
// and require that the PORT routines only be used for access to IO
// space.
//
ldiq t4, EISA_IO # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t4, IO_HI_SHIFT, t4 # shift bits PA<63:32> into position
or t0, t4, t0 # generate superpage address
20:
ldl t1, (a1) # a1 must be longword aligned
subl a2, 1, a2 # decrement count
stl t1, EISA_LONG_LEN(t0) # store longword to port
mb # push writes off chip
addl a1, 4, a1 # increment buffer pointer
bne a2, 20b # loop if more bytes to move
30:
ret zero, (ra)
#if DBG
40:
//
// HAE is non-zero or not a bus address, this should never happen!
//
BREAK_DEBUG_STOP
or a0, zero, a2 # save bad address in a2
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if illegal access
#endif
.end WRITE_PORT_BUFFER_ULONG
LEAF_ENTRY(READ_REGISTER_BUFFER_UCHAR)
/*++
Routine Description:
Reads from the specified buffer address. This routine only works
with EISA memory space, since there are no REGISTER buffers in
COMBO space on Jensen.
Arguments:
a0 QVA of source buffer.
a1 VA of destination buffer in memory.
a2 Number of bytes to move (Count).
Return Value:
None
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get byte within longword
bne t1, 120f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
or t0, t2, t0 # generate superpage address
//
// Note - at this point we know bits t0<63:25> = 0
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 130f # br if HAE has to be set up
//
// get source buffer aligned
//
// t0 = superpage bus address of source
// a1 = destination va
// a2 = byte count
// t3 = byte offset (in a LONGWORD)
//
ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
and t0, t10, t9 # t9 holds EISA address bits 1..0
srl t9, EISA_BIT_SHIFT, t9 # position bits down low
and a1, 3, t8 # 1..0 of destination VA
xor t9, t8, t8 # compare alignment of src and dst
bne t8, 70f # use unaligned code if not aligned
// transfer can be done using longword fetch/store since the
// source and destination are sympathetically aligned
beq t9, 20f # branch if src is already longaligned
// Move bytes until source is at a longword boundary
10: beq a2, 60f # while count > 0
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
extbl v0, t3, v0 # get the correct byte
stb v0, (a1) # cheat and let the assembler do it
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
bne t3, 10b # while unaligned loop here
// move aligned longwords
20: srl a2, 2, t3 # longwords to move
beq t3, 40f # done moving longwords?
lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
30: ldl t4, EISA_LONG_LEN(t0) # fetch longword from EISA
addl a1, 4, a1 # increment dst VA
subl t3, 1, t3 # decr longwords to move
stl t4, -4(a1) # store to dst
addq t0, t11, t0 # increment src pointer
bne t3, 30b # while longwords remain
40: and a2, 3, a2 # bytes remaining
//bis zero, zero, t3 # byte lane 0
// non-aligned and driblets move
50: beq a2, 60f # while count > 0
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
extbl v0, t3, v0 # get the correct byte
stb v0, (a1) # cheat and let the assembler do it
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
br zero, 50b # end while
60:
ret zero, (ra)
//
// source EISA alignment != destination memory alignment
// move enough bytes to longword align the EISA source
// then move 32bit (longwords) storing unaligned into memory
// then move residual bytes
//
// t0 = superpage address of source
// a1 = virtual address of destination
// a2 = bytes to move
// t9 = low 2 bits of EISA superpage address
// t3 = low 2 bits of EISA QVA
//
70:
beq t9, 90f # branch if src is longaligned
// Move bytes until EISA src is at a longword boundary or bytes exhausted
80: beq a2, 60b # while count > 0
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
extbl v0, t3, v0 # get the correct byte
stb v0, (a1) # cheat and let the assembler do it
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
bne t3, 80b # while not aligned
// align EISA source, unaligned memory destination
90:
srl a2, 3, t3 # t3 = quadwords to move
beq t3, 110f # finish if no longwords
100:
ldl t1, EISA_LONG_LEN(t0) # load longword 0 from EISA
ldq_u t4, 0(a1) # load destination quad for merge
ldq_u t5, 7(a1) #
subl t3, 1, t3 # decrement quadwords to move
ldl t2, EISA_SECOND_LONG(t0) # load longword 1 from EISA
mskql t4, a1, t4 # mask of merge bytes
mskqh t5, a1, t5 # mask of merge bytes
zap t1, 0xf0, t1 # clear high longword for long 0
sll t2, 32, t2 # get long 1 to high longword
bis t1, t2, t1 # merge read quadword together
lda t0, EISA_QUAD_OFFSET(t0) # increment to next quadword
insql t1, a1, t6 # position low quadword for merge
insqh t1, a1, t7 # position high quadword for merge
bis t4, t6, t4 # merge new data, low quadword
bis t5, t7, t5 # merge new data, high quadword
stq_u t5, 7(a1) # write high quadword
stq_u t4, 0(a1) # write low quadword
lda a1, 8(a1) # increment memory pointer
bne t3, 100b # while quadwords to move
110:
and a2, 7, a2 # bytes remaining to move
//bis zero, zero, t3 # byte line position of next byte
br zero, 50b # go back to byte mover
120:
//
// This must be non I/O space access
//
bis a0, zero, t0 # save source address
bis a1, zero, a0 # move destination address to a0
bis t0, zero, a1 # move source address to a1
br zero, RtlMoveMemory # Let Rtl routine handle move
130:
//
// setup HAE
//
// a0 = QVA
// a1 = destination va
// a2 = byte count
// t0 = superpage bus address of source
// t3 = byte offset (in a LONGWORD)
// t4 = HAE index
// t2 = upper bits of EISA superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 250f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
bis t6, zero, a1 # restore a1
bis t7, zero, a2 # restore a2
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t8, (t1) # get original HAE value
bne t8, 250f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the bytes from the EISA bus
//
// t8 = original HAE value (debug only)
// a0 = original IRQL
//
// t0 = superpage bus address of source
// t1 = address of HAE register
// a1 = destination va
// a2 = byte count
// t3 = byte offset (in a LONGWORD)
//
ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
and t0, t10, t9 # t9 holds EISA address bits 1..0
srl t9, EISA_BIT_SHIFT, t9 # position bits down low
and a1, 3, t10 # 1..0 of destination VA
xor t9, t10, t10 # compare alignment of src and dst
bne t10, 200f # use unaligned code if not aligned
// transfer can be done using longword fetch/store since the
// source and destination are sympathetically aligned
beq t9, 150f # branch if src is already longaligned
// Move bytes until source is at a longword boundary
140: beq a2, 190f # while count > 0
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
extbl v0, t3, v0 # get the correct byte
stb v0, (a1) # cheat and let the assembler do it
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
bne t3, 140b # while unaligned loop here
// move aligned longwords
150: srl a2, 2, t3 # longwords to move
beq t3, 170f # done moving longwords?
lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
160: ldl t4, EISA_LONG_LEN(t0) # fetch longword from EISA
addl a1, 4, a1 # increment dst VA
subl t3, 1, t3 # decr longwords to move
stl t4, -4(a1) # store to dst
addq t0, t11, t0 # increment src pointer
bne t3, 160b # while longwords remain
170: and a2, 3, a2 # bytes remaining
//bis zero, zero, t3 # byte lane 0
// non-aligned and driblets move
180: beq a2, 190f # while count > 0
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
extbl v0, t3, v0 # get the correct byte
stb v0, (a1) # cheat and let the assembler do it
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
br zero, 180b # end while
190:
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL, original IRQL in a0
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
//
// source EISA alignment != destination memory alignment
// move enough bytes to longword align the EISA source
// then move 32bit (longwords) storing unaligned into memory
// then move residual bytes
//
// t8 = original HAE value (debug only)
// a0 = original IRQL
//
// t0 = superpage address of source
// a1 = virtual address of destination
// a2 = bytes to move
// t9 = low 2 bits of EISA superpage address
// t3 = low 2 bits of EISA QVA
//
200:
beq t9, 220f # branch if src is longaligned
// Move bytes until EISA src is at a longword boundary or bytes exhausted
210: beq a2, 190b # while count > 0
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
extbl v0, t3, v0 # get the correct byte
stb v0, (a1) # cheat and let the assembler do it
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
bne t3, 210b # while not aligned
// align EISA source, unaligned memory destination
220:
srl a2, 3, t3 # t3 = quadwords to move
beq t3, 240f # finish if no longwords
230:
ldl v0, EISA_LONG_LEN(t0) # load longword 0 from EISA
ldq_u t4, 0(a1) # load destination quad for merge
ldq_u t5, 7(a1) #
subl t3, 1, t3 # decrement quadwords to move
ldl t2, EISA_SECOND_LONG(t0) # load longword 1 from EISA
mskql t4, a1, t4 # mask of merge bytes
mskqh t5, a1, t5 # mask of merge bytes
zap v0, 0xf0, v0 # clear high longword for long 0
sll t2, 32, t2 # get long 1 to high longword
bis v0, t2, v0 # merge read quadword together
lda t0, EISA_QUAD_OFFSET(t0) # increment to next quadword
insql v0, a1, t6 # position low quadword for merge
insqh v0, a1, t7 # position high quadword for merge
bis t4, t6, t4 # merge new data, low quadword
bis t5, t7, t5 # merge new data, high quadword
stq_u t5, 7(a1) # write high quadword
stq_u t4, 0(a1) # write low quadword
lda a1, 8(a1) # increment memory pointer
bne t3, 230b # while quadwords to move
240:
and a2, 7, a2 # bytes remaining to move
//bis zero, zero, t3 # byte line position of next byte
br zero, 180b # go back to byte mover
#if DBG
250:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end READ_REGISTER_BUFFER_UCHAR
LEAF_ENTRY(READ_REGISTER_BUFFER_USHORT)
/*++
Routine Description:
Reads from the specified buffer address. This routine only works
with EISA memory space, since there are no REGISTER buffers in
COMBO space on Jensen.
Both the input buffer and output buffer should be word aligned.
Arguments:
a0 QVA of source buffer.
a1 VA of destination buffer in memory.
a2 Number of words to move (Count).
Return Value:
None
--*/
beq a2, 30f # leave is nothing to do
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get byte within longword
bne t1, 40f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index alone
bic a0, t0, t0 # clear QVA control bits a0<63:25>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
or t0, t2, t0 # generate superpage address
or t0, EISA_WORD_LEN, t0 # or in the WORD byte enables
//
// Note - at this point we know bits t0<63:25> = 0
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 100f # br if HAE has to be set up
20:
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
extwl v0, t3, v0 # get the correct
stw v0, (a1) # cheat and let the assembler do it
addl a1, 2, a1 # next word in buffer
addq t0, EISA_SHORT_OFFSET, t0 # next I/O address
addl t3, 2, t3 # next word in lane
and t3, 3, t3 # longword lanes
bne a2, 20b # end while
30:
ret zero, (ra)
40:
//
// This must be non I/O space access
//
bis a0, zero, t0 # save source address
sll a2, 1, a2 # convert word count to byte count
bis a1, zero, a0 # move destination address to a0
bis t0, zero, a1 # move source address to a1
br zero, RtlMoveMemory # Let Rtl routine handle move
100:
//
// setup HAE
//
// a0 = QVA of source
// a1 = destination va
// a2 = word count
// t0 = superpage bus address of source
// t3 = byte offset for source (within a LONGWORD)
// t4 = HAE index
// t2 = upper bits of EISA superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 150f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t8, (t1) # get original HAE value
bne t8, 150f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the words from the EISA bus
//
// t8 = original HAE value (debug only)
// a0 = original IRQL
//
// t0 = superpage bus address of source
// t1 = address of HAE register
// t6 = destination va
// t7 = word count
// t3 = byte offset for source (within a LONGWORD)
//
120:
ldl v0, 0(t0) # get the longword
subl t7, 1, t7 # decrement count
extwl v0, t3, v0 # get the correct
stw v0, (t6) # cheat and let the assembler do it
addl t6, 2, t6 # next word in buffer
addq t0, EISA_SHORT_OFFSET, t0 # next I/O address
addl t3, 2, t3 # next word in lane
and t3, 3, t3 # longword lanes
bne t7, 120b # end while
130:
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL, original IRQL in a0
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
#if DBG
150:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end READ_REGISTER_BUFFER_USHORT
LEAF_ENTRY(READ_REGISTER_BUFFER_ULONG)
/*++
Routine Description:
Reads from the specified buffer address. This routine only works
with EISA memory space, since there are no REGISTER buffers in
COMBO space on Jensen.
Both the input buffer and output buffer should be longword aligned.
Arguments:
a0 QVA of source buffer.
a1 VA of destination buffer in memory.
a2 Number of longs to move (Count).
Return Value:
None
--*/
beq a2, 30f # leave if nothing to do
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
or t0, t2, t0 # generate superpage address
or t0, EISA_LONG_LEN, t0 # or in the LONGWORD byte enables
//
// Note - at this point we know bits t0<63:25> = 0
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 100f # br if HAE has to be set up
20:
ldl v0, 0(t0) # get the longword
subl a2, 1, a2 # decrement count
stl v0,(a1) # cheat and let the assembler do it
addl a1, 4, a1 # next longword in buffer
addq t0, EISA_LONG_OFFSET, t0 # next I/O address
bne a2, 20b # end while
30:
ret zero, (ra)
40:
//
// This must be non I/O space access
//
bis a0, zero, t0 # save source address
s4addl a2, zero, a2 # convert longword count to byte count
bis a1, zero, a0 # move destination address to a0
bis t0, zero, a1 # move source address to a1
br zero, RtlMoveMemory # Let Rtl routine handle move
100:
//
// setup HAE
//
// a0 = QVA of source
// a1 = destination va
// a2 = longword count
// t0 = superpage bus address of source
// t4 = HAE index
// t2 = upper bits of EISA superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 150f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t8, (t1) # get original HAE value
bne t8, 150f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the words from the EISA bus
//
// t8 = original HAE value (debug only)
// a0 = original IRQL
//
// t0 = superpage bus address of source
// t1 = address of HAE register
// t6 = destination va
// t7 = longword count
//
120:
ldl v0, 0(t0) # get the longword
subl t7, 1, t7 # decrement count
stl v0, (t6) # cheat and let the assembler do it
addl t6, 4, t6 # next word in buffer
addq t0, EISA_LONG_OFFSET, t0 # next I/O address
bne t7, 120b # end while
130:
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL, original IRQL in a0
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
#if DBG
150:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end READ_REGISTER_BUFFER_ULONG
LEAF_ENTRY(WRITE_REGISTER_BUFFER_UCHAR)
/*++
Routine Description:
Writes to the specified buffer address. This routine only works
with EISA memory space, since there are no REGISTER buffers in
COMBO space on Jensen.
Arguments:
a0 QVA of destination buffer in I/O space.
a1 VA of source buffer in memory.
a2 Number of bytes to move (Count).
Return Value:
None
--*/
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get byte within longword
bne t1, 120f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
or t0, t2, t0 # generate superpage address
//
// Note - at this point we know bits t0<63:25> = 0
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 130f # br if HAE has to be set up
//
//
// get destination buffer aligned
//
// t0 = superpage destination bus address
// a1 = source va
// a2 = byte count
// t3 = byte offset (in a LONGWORD)
//
ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
and t0, t10, t9 # t9 holds EISA address bits 1..0
srl t9, EISA_BIT_SHIFT, t9 # position bits
and a1, 3, t8 # 1..0 of destination VA
xor t9, t8, t8 # compare alignment of src and dst
bne t8, 70f # use unaligned move if not aligned
// transfer can be done using longword fetch/store since the
// source and destination are sympathetically aligned
beq t9, 20f # br if dest is already longaligned
// Move bytes until destination is at a longword boundary or bytes exhausted
10: beq a2, 60f # while count > 0
ldq_u t1, 0(a1) # get quad surrounding byte
subl a2, 1, a2 # decrement count
extbl t1, a1, t1 # extract appropriate byte
addl a1, 1, a1 # increment buffer pointer
insbl t1, t3, t1 # get proper lane
stl t1, 0(t0) # store to buffer
addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
addl t3, 1, t3
and t3, 3, t3 # longwords only
bne t3, 10b # loop if not long aligned
// move aligned longwords
20: srl a2, 2, t3 # longwords to move
beq t3, 40f # done moving longwords?
lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
30: ldl t4, 0(a1) # fetch longword from memory
addl a1, 4, a1 # increment to next longword
subl t3, 1, t3 # decrement longwords to move
stl t4, EISA_LONG_LEN(t0) # store longword to EISA
addq t0, t11, t0 # increment EISA pointer
bne t3, 30b # while longwords remain
40: and a2, 3, a2 # bytes remaining
//bis zero, zero, t3 # byte lane 0
// non-aligned and driblets move
50: beq a2, 60f # copy while a2 > 0
ldq_u t1, 0(a1) # get quad surrounding byte
subl a2, 1, a2 # decrement count
extbl t1, a1, t1 # extract appropriate byte
addl a1, 1, a1 # increment buffer pointer
insbl t1, t3, t1 # get proper lane
stl t1, 0(t0) # store to buffer
addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
addl t3, 1, t3
and t3, 3, t3 # longwords only
br zero, 50b # end while
60: mb
ret zero, (ra)
//
// source EISA alignment != destination memory alignment
// move enough bytes to longword align the EISA destination
// then move 32bit (longwords) reading unaligned data from memory
// then move residual bytes
//
// t0 = superpage address of destination
// a1 = virtual address of source
// a2 = bytes to move
// t9 = low 2 bits of EISA superpage address
// t3 = low 2 bits of EISA QVA
//
70:
beq t9, 90f # branch if destination is longaligned
// Move bytes until EISA src is at a longword boundary or bytes exhausted
80: beq a2, 60b # while count > 0
ldq_u v0, 0(a1) # get byte
extbl v0, a1, v0 #
insbl v0, t3, v0 # get proper lane
stl v0, 0(t0) # store byte to EISA buffer
subl a2, 1, a2 # decrement count
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
bne t3, 80b # loop while not aligned
// aligned EISA source, unaligned memory destination
90:
srl a2, 3, t3 # t3 = quadwords to move
beq t3, 110f # finish if no quadwords
100:
ldq_u t1, 0(a1) # load low source quadword
ldq_u t2, 7(a1) # load high source quadword
extql t1, a1, t1 # extract low portion of quadword
extqh t2, a1, t2 # extract high portion of quadword
bis t1, t2, t1 # merge to get source quadword
stl t1, EISA_LONG_LEN(t0) # store low longword to EISA
lda a1, 8(a1) # increment to next source quadword
srl t1, 32, t1 # get high longword into position
subl t3, 1, t3 # decrement quadwords to move
stl t1, EISA_SECOND_LONG(t0) # store high longword
lda t0, EISA_QUAD_OFFSET(t0) # increment to next dest. quadword
bne t3, 100b # while quadwords to move
110:
and a2, 7, a2 # bytes remaining to move
//bis zero, zero, t3 # byte line position of next byte
br zero, 50b # go back to byte mover
120:
//
// This must be non I/O space access
//
br zero, RtlMoveMemory # Let Rtl routine handle move
130:
//
// setup HAE
//
// a0 = QVA
// a1 = source va
// a2 = byte count
// t0 = superpage bus address of destination
// t3 = byte offset for destination (within a LONGWORD)
// t4 = HAE index
// t2 = upper bits of EISA superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 250f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
bis t6, zero, a1 # restore a1
bis t7, zero, a2 # restore a2
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t8, (t1) # get original HAE value
bne t8, 250f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can write the bytes to the EISA bus
//
// t8 = original HAE value (debug only)
// a0 = original IRQL
//
// t0 = superpage bus address of destination
// t1 = address of HAE register
// a1 = source va
// a2 = byte count
// t3 = byte offset of destination (within a LONGWORD)
//
ldiq t10, EISA_BITS_ONEZERO # mask for EISA address 1..0
and t0, t10, t9 # t9 holds EISA address bits 1..0
srl t9, EISA_BIT_SHIFT, t9 # position bits
and a1, 3, t10 # 1..0 of destination VA
xor t9, t10, t10 # compare alignment of src and dst
bne t10, 200f # use unaligned move if not aligned
// transfer can be done using longword fetch/store since the
// source and destination are sympathetically aligned
beq t9, 150f # br if dest is already longaligned
// Move bytes until destination is at a longword boundary or bytes exhausted
140: beq a2, 190f # while count > 0
ldq_u v0, 0(a1) # get quad surrounding byte
subl a2, 1, a2 # decrement count
extbl v0, a1, v0 # extract appropriate byte
addl a1, 1, a1 # increment buffer pointer
insbl v0, t3, v0 # get proper lane
stl v0, 0(t0) # store to buffer
addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
addl t3, 1, t3
and t3, 3, t3 # longwords only
bne t3, 140b # loop if not long aligned
// move aligned longwords
150: srl a2, 2, t3 # longwords to move
beq t3, 170f # done moving longwords?
lda t11, EISA_LONG_OFFSET(zero) # longword stride in EISA space
160: ldl t4, 0(a1) # fetch longword from memory
addl a1, 4, a1 # increment to next longword
subl t3, 1, t3 # decrement longwords to move
stl t4, EISA_LONG_LEN(t0) # store longword to EISA
addq t0, t11, t0 # increment EISA pointer
bne t3, 160b # while longwords remain
170: and a2, 3, a2 # bytes remaining
//bis zero, zero, t3 # byte lane 0
// non-aligned and driblets move
180: beq a2, 190f # copy while a2 > 0
ldq_u v0, 0(a1) # get quad surrounding byte
subl a2, 1, a2 # decrement count
extbl v0, a1, v0 # extract appropriate byte
addl a1, 1, a1 # increment buffer pointer
insbl v0, t3, v0 # get proper lane
stl v0, 0(t0) # store to buffer
addq t0, EISA_BYTE_OFFSET, t0 # increment I/O buffer
addl t3, 1, t3
and t3, 3, t3 # longwords only
br zero, 180b # end while
190:
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out + previous writes
//
// Lower IRQL, original IRQL in a0
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
//
// source EISA alignment != destination memory alignment
// move enough bytes to longword align the EISA destination
// then move 32bit (longwords) reading unaligned data from memory
// then move residual bytes
//
// t0 = superpage address of destination
// a1 = virtual address of source
// a2 = bytes to move
// t9 = low 2 bits of EISA superpage address
// t3 = low 2 bits of EISA QVA
//
200:
beq t9, 220f # branch if destination is longaligned
// Move bytes until EISA src is at a longword boundary or bytes exhausted
210: beq a2, 190b # while count > 0
ldq_u v0, 0(a1) # get byte
extbl v0, a1, v0 #
insbl v0, t3, v0 # get proper lane
stl v0, 0(t0) # store byte to EISA buffer
subl a2, 1, a2 # decrement count
addl a1, 1, a1 # next byte in buffer
addq t0, EISA_BYTE_OFFSET, t0 # next I/O address
addl t3, 1, t3 # next byte in lane
and t3, 3, t3 # longword lanes
bne t3, 210b # loop while not aligned
// aligned EISA source, unaligned memory destination
220:
srl a2, 3, t3 # t3 = quadwords to move
beq t3, 240f # finish if no quadwords
230:
ldq_u v0, 0(a1) # load low source quadword
ldq_u t2, 7(a1) # load high source quadword
extql v0, a1, v0 # extract low portion of quadword
extqh t2, a1, t2 # extract high portion of quadword
bis v0, t2, v0 # merge to get source quadword
stl v0, EISA_LONG_LEN(t0) # store low longword to EISA
lda a1, 8(a1) # increment to next source quadword
srl v0, 32, v0 # get high longword into position
subl t3, 1, t3 # decrement quadwords to move
stl v0, EISA_SECOND_LONG(t0) # store high longword
lda t0, EISA_QUAD_OFFSET(t0) # increment to next dest. quadword
bne t3, 230b # while quadwords to move
240:
and a2, 7, a2 # bytes remaining to move
//bis zero, zero, t3 # byte line position of next byte
br zero, 180b # go back to byte mover
#if DBG
250:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end WRITE_REGISTER_BUFFER_UCHAR
LEAF_ENTRY(WRITE_REGISTER_BUFFER_USHORT)
/*++
Routine Description:
Writes to the specified buffer address. This routine only works
with EISA memory space, since there are no REGISTER buffers in
COMBO space on Jensen.
Both the input buffer and output buffer should be word aligned.
Arguments:
a0 QVA of destination buffer.
a1 VA of source buffer in memory.
a2 Number of bytes to move (Count).
Return Value:
None
--*/
beq a2, 30f # leave if nothing to do
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
and a0, 3, t3 # get byte within longword
bne t1, 40f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
or t0, t2, t0 # generate superpage address
or t0, EISA_WORD_LEN, t0 # or in the WORD byte enables
//
// Note - at this point we know bits t0<63:25> = 0
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 100f # br if HAE has to be set up
20:
ldq_u t1, 0(a1) # get quad surrounding word
subl a2, 1, a2 # decrement count
extwl t1, a1, t1 # extract appropriate word
addl a1, 2, a1 # increment buffer pointer
inswl t1, t3, t1 # get proper lane
stl t1, 0(t0) # store to buffer
addq t0, EISA_SHORT_OFFSET, t0 # increment I/O buffer
addl t3, 2, t3
and t3, 3, t3 # longwords only
bne a2, 20b # end while
30:
ret zero, (ra)
40:
//
// This must be non I/O space access
//
sll a2, 1, a2 # convert word count to byte count
br zero, RtlMoveMemory # Let Rtl routine handle move
100:
//
// setup HAE
//
// a0 = QVA of destination
// a1 = source va
// a2 = word count
// t0 = superpage bus address of destination
// t3 = byte offset for destination (within a LONGWORD)
// t4 = HAE index
// t2 = upper bits of EISA superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 150f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t8, (t1) # get original HAE value
bne t8, 150f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the words from the EISA bus
//
// t8 = original HAE value (debug only)
// a0 = original IRQL
//
// t0 = superpage bus address of source
// t1 = address of HAE register
// t6 = destination va
// t7 = word count
// t3 = byte offset for source (within a LONGWORD)
//
120:
ldq_u v0, 0(t6) # get quad surrounding word
subl t7, 1, t7 # decrement count
extwl v0, t6, v0 # extract appropriate word
addl t6, 2, t6 # increment buffer pointer
inswl v0, t3, v0 # get proper lane
stl v0, 0(t0) # store to buffer
addq t0, EISA_SHORT_OFFSET, t0 # increment I/O buffer
addl t3, 2, t3
and t3, 3, t3 # longwords only
bne t7, 120b # end while
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL, original IRQL in a0
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
#if DBG
150:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end WRITE_REGISTER_BUFFER_USHORT
LEAF_ENTRY(WRITE_REGISTER_BUFFER_ULONG)
/*++
Routine Description:
Writes to the specified buffer address. This routine only works
with EISA memory space, since there are no REGISTER buffers in
COMBO space on Jensen.
Both the input buffer and output buffer should be longword aligned.
Arguments:
a0 QVA of destination buffer in I/O space.
a1 VA of source buffer in memory.
a2 Number of longwords to move (Count).
Return Value:
None
--*/
beq a2, 30f # leave if nothing to do
srl a0, QVA_HAE_SHIFT, t2 # get control and HAE index bits
and t2, QVA_SELECTORS_SHIFTED, t1 # get QVA selector bits
xor t1, QVA_ENABLE_SHIFTED, t1 # ok iff QVA_ENABLE set in selectors
bne t1, 40f # br if not a bus address
ldah t0, QVA_CONTROL(zero) # get mask clear bits
and t2, 3, t4 # get HAE index
bic a0, t0, t0 # clear QVA control bits a0<63:25>
ldiq t2, EISA_MEMORY # form upper bits of PA
sll t0, EISA_BIT_SHIFT, t0 # t0 contains PA<31:0>
sll t2, IO_HI_SHIFT, t2 # shift upper bits into position
or t0, t2, t0 # generate superpage address
or t0, EISA_LONG_LEN, t0 # or in the byte enables
//
// Note - at this point we know bits t0<63:25> = 0
//
// Check if we have to load the HAE with a non-zero value. This
// is considered non-standard, but it is supported. Loading the HAE
// requires additional synchronization.
//
bne t4, 100f # br if HAE has to be set up
20:
ldl t1, 0(a1) # get longword
subl a2, 1, a2 # decrement count
addl a1, 4, a1 # increment buffer pointer
stl t1, 0(t0) # store to buffer
addq t0, EISA_LONG_OFFSET, t0 # increment I/O buffer
bne a2, 20b # end while
30:
ret zero, (ra)
40:
//
// This must be non I/O space access
//
s4addl a2, zero, a2 # convert longword count to byte count
br zero, RtlMoveMemory # Let Rtl routine handle move
100:
//
// setup HAE
//
// a0 = QVA of destination
// a1 = source va
// a2 = longword count
// t0 = superpage bus address of destination
// t4 = HAE index
// t2 = upper bits of EISA superpage address
//
lda t1, HalpHaeTable # get address of HAE table
ldiq t2, COMBO_IO # form upper bits of HAE
addl t4, t1, t1 # get address of new HAE value
sll t2, IO_HI_SHIFT, t2 # shift bits PA<63:32> into position
ldq_u t4, (t1) # get new HAE value
extbl t4, t1, t4 # ...
#if DBG
// Note: the value in t4 should never be zero!
beq t4, 150f # br if new HAE value is zero!
#endif
ldiq t1, HAE_PHYSICAL_BASEL # get base address of HAE register
or t1, t2, t1 # generate HAE superpage address
bis a1, zero, t6 # save a1, since SWAP_IRQL destroys it
bis a2, zero, t7 # save a2, since SWAP_IRQL destroys it
//
// Raise IRQL to device level to block other accesses to EISA memory
//
ldiq a0, DEVICE_LEVEL # get device level IRQL
SWAP_IRQL # raise IRQL to DEVICE_LEVEL
bis v0, zero, a0 # save original IRQL
//
// We will not bother to save the original HAE value. The value
// in the HAE must be zero... otherwise synchronization is broken.
// In debug mode, we will check the HAE however.
//
#if DBG
ldl t8, (t1) # get original HAE value
bne t8, 150f # br if HAE is non-zero - error!
#endif
stl t4, (t1) # write new HAE value
mb # force it out
//
// Now we can read the words from the EISA bus
//
// t8 = original HAE value (debug only)
// a0 = original IRQL
//
// t0 = superpage bus address of source
// t1 = address of HAE register
// t6 = destination va
// t7 = word count
// t3 = byte offset for source (within a LONGWORD)
//
120:
ldl v0, 0(t6) # get longword
subl t7, 1, t7 # decrement count
addl t6, 4, t6 # increment buffer pointer
stl v0, 0(t0) # store to buffer
addq t0, EISA_LONG_OFFSET, t0 # increment I/O buffer
bne t7, 120b # end while
//
// Restore HAE before exiting
//
stl zero, (t1) # restore original HAE value
mb # force it out
//
// Lower IRQL, original IRQL in a0
//
SWAP_IRQL # restore original IRQL
ret zero, (ra)
#if DBG
150:
// New HAE value is zero!
BREAK_DEBUG_STOP
ldil a0, BAD_QVA
jsr t12, KeBugCheck # crash if bad HAE index
#endif
.end WRITE_REGISTER_BUFFER_ULONG