272 lines
8.2 KiB
Plaintext
272 lines
8.2 KiB
Plaintext
|
// TITLE("Compute Checksum")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
//
|
|||
|
// Module Name:
|
|||
|
//
|
|||
|
// xsum.s
|
|||
|
//
|
|||
|
// Abstract:
|
|||
|
//
|
|||
|
// This module implements a function to compute the checksum of a buffer.
|
|||
|
//
|
|||
|
// Author:
|
|||
|
//
|
|||
|
// John Vert (jvert) 11-Jul-1994
|
|||
|
//
|
|||
|
// Environment:
|
|||
|
//
|
|||
|
// Revision History:
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#include "ksalpha.h"
|
|||
|
|
|||
|
|
|||
|
SBTTL("Compute Checksum")
|
|||
|
//++
|
|||
|
//
|
|||
|
// ULONG
|
|||
|
// tcpxsum (
|
|||
|
// IN ULONG Checksum,
|
|||
|
// IN PUSHORT Source,
|
|||
|
// IN ULONG Length
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This function computes the checksum of the specified buffer.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// Checksum (a0) - Supplies the initial checksum value.
|
|||
|
//
|
|||
|
// Source (a1) - Supplies a pointer to the checksum buffer
|
|||
|
//
|
|||
|
// Length (a2) - Supplies the length of the buffer in words.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// The computed checksum is returned as the function value.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(tcpxsum)
|
|||
|
zap a0, 0xf0, a0 // clear high half of a0
|
|||
|
bis a1, zero, t6 // save initial buffer address
|
|||
|
bis zero, zero, v0 // clear accumulated checksum
|
|||
|
|
|||
|
//
|
|||
|
// Check if the buffer is quadword aligned.
|
|||
|
//
|
|||
|
// If the buffer is not quadword aligned, then add the leading words to the
|
|||
|
// checksum.
|
|||
|
//
|
|||
|
ldq_u t0, 0(a1) // get containing quadword of first part
|
|||
|
blbc a1, 10f // check for word alignment
|
|||
|
beq a2, 65f // if zero bytes, don't do anything
|
|||
|
extbl t0, a1, t1 // get leading byte
|
|||
|
sll t1, 8, v0 // shift it to correct spot for later byte swap
|
|||
|
addq a1, 1, a1 // increment buffer to first full word
|
|||
|
subq a2, 1, a2 // decrement byte count
|
|||
|
|
|||
|
10:
|
|||
|
and a1, 6, t2 // check if buffer quadword aligned
|
|||
|
beq t2, 20f // if eq, quadword aligned
|
|||
|
extql t0, t2, t0 // extract bytes to checksum
|
|||
|
and a1, 7, t3 // compute bytes summed
|
|||
|
subq zero, t3, t3
|
|||
|
addq t3, 8, t3
|
|||
|
addq a1, 8, a1 // advance buffer address to next qword
|
|||
|
bic a1, 7, a1 //
|
|||
|
subq a2, t3, t2
|
|||
|
blt t2, 55f // if ltz, too many, jump to residual code
|
|||
|
|
|||
|
addq v0, t0, v0 // add bytes to partial checksum
|
|||
|
cmpult v0, t0, t1 // generate carry
|
|||
|
addq t1, v0, v0 // add carry back into checksum
|
|||
|
|
|||
|
bis t2, zero, a2 // reduce count of bytes to checksum
|
|||
|
beq t2, 60f // if eq, no more bytes
|
|||
|
|
|||
|
20:
|
|||
|
//
|
|||
|
// Compute the checksum in 64-byte blocks
|
|||
|
//
|
|||
|
bic a2, 7, t4 // subtract out residual bytes
|
|||
|
beq t4, 40f // if eq, no quadwords to checksum
|
|||
|
subq zero, t4, t2 // compute negative of byte count
|
|||
|
and t2, 15 << 2, t3 // compute bytes in first iteration
|
|||
|
ldq t0, 0(a1) // get first quadword to checksum
|
|||
|
beq t3, 35f // if eq, full 64-byte block
|
|||
|
subq a1, t3, a1 // bias buffer address by offset
|
|||
|
bic t4, 64-1, t4 // subtract out bytes in first iteration
|
|||
|
lda t2, 30f // get base address of code vector
|
|||
|
addl t3, t3, t3 //
|
|||
|
addq t3, t2, t2 // compute code vector offset
|
|||
|
bis t0, zero, t1 // copy first quadword to checksum
|
|||
|
jmp (t2) // dispatch
|
|||
|
|
|||
|
|
|||
|
30:
|
|||
|
//
|
|||
|
// The following code vector computes the checksum of a 64-byte block.
|
|||
|
//
|
|||
|
.set noreorder
|
|||
|
ldq t1, 8(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t0, 16(a1)
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t1, 24(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t0, 32(a1)
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t1, 40(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t0, 48(a1)
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t1, 56(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
addq a1, 64, a1
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
.set reorder
|
|||
|
|
|||
|
beq t4, 40f // if zero, end of block
|
|||
|
|
|||
|
35:
|
|||
|
ldq t0, 0(a1)
|
|||
|
//
|
|||
|
// The following loop is allowed to be reordered by the assembler for
|
|||
|
// optimal scheduling. It is never branched into.
|
|||
|
//
|
|||
|
subq t4, 64, t4 // reduce byte count of longwords
|
|||
|
|
|||
|
ldq t1, 8(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t0, 16(a1)
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t1, 24(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t0, 32(a1)
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t1, 40(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t0, 48(a1)
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
ldq t1, 56(a1)
|
|||
|
addq v0, t0, v0
|
|||
|
cmpult v0, t0, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
addq a1, 64, a1
|
|||
|
addq v0, t1, v0
|
|||
|
cmpult v0, t1, t2
|
|||
|
addq v0, t2, v0
|
|||
|
|
|||
|
bne t4, 35b // if ne zero, not end of block
|
|||
|
|
|||
|
40:
|
|||
|
//
|
|||
|
// Check for any remaining bytes.
|
|||
|
//
|
|||
|
and a2, 7, a2 // isolate residual bytes
|
|||
|
beq a2, 60f // if eq, no residual bytes
|
|||
|
50:
|
|||
|
//
|
|||
|
// Checksum remaining bytes.
|
|||
|
//
|
|||
|
// The technique we use here is to load the final quadword, then
|
|||
|
// zero out the bytes that are not included.
|
|||
|
//
|
|||
|
ldq t0, 0(a1) // get quadword surrounding remainder
|
|||
|
55:
|
|||
|
ornot zero, zero, t1 // get FF mask
|
|||
|
sll t1, a2, t2 // shift to produce byte mask
|
|||
|
zap t0, t2, t0 // zero out bytes past end of buffer
|
|||
|
addq v0, t0, v0 // add quadword to partial checksum
|
|||
|
cmpult v0, t0, t1 // generate carry
|
|||
|
addq t1, v0, v0 // add carry back into checksum
|
|||
|
60:
|
|||
|
//
|
|||
|
// Byte swap the 64-bit checksum if the start of the buffer was not word aligned
|
|||
|
//
|
|||
|
blbc t6, 65f
|
|||
|
zap v0, 0xAA, t0 // isolate even bytes
|
|||
|
sll t0, 8, t0 // shift even bytes into odd positions
|
|||
|
srl v0, 8, t1 // shift odd bytes into even positions
|
|||
|
zap t1, 0xAA, t1 // isolate odd bytes
|
|||
|
bis t0, t1, v0 // merge bytes back together
|
|||
|
|
|||
|
65:
|
|||
|
//
|
|||
|
// add computed checksum to original checksum, and fold the 64-bit
|
|||
|
// result down to 16 bits.
|
|||
|
//
|
|||
|
addq v0, a0, v0 // add computed checksum to original
|
|||
|
cmpult v0, a0, t0 // generate carry
|
|||
|
addq v0, t0, v0 // add carry back into checksum
|
|||
|
|
|||
|
//
|
|||
|
// swap the longwords in order to sum two longwords and their carry in one add.
|
|||
|
//
|
|||
|
sll v0, 32, t0 // shift low longword into high
|
|||
|
srl v0, 32, t1 // shift high longword into low
|
|||
|
bis t1, t0, t5 // merge back together
|
|||
|
|
|||
|
addq v0, t5, t0 // produce sum + carry in high longword
|
|||
|
srl t0, 32, t1 // shift back down to low half
|
|||
|
//
|
|||
|
// swap the words in order to sum two words and their carry in one add
|
|||
|
//
|
|||
|
sll t1, 16, t2 // shift high word into low
|
|||
|
srl t1, 16, t3 // shift low word into high
|
|||
|
bis t2, t3, t4 // merge back together
|
|||
|
addq t4, t1, t2 // produce sum and carry in high word
|
|||
|
extwl t2, 2, v0 // extract result.
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end tcpxsum
|
|||
|
|