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.
3523 lines
92 KiB
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
|
|
|