]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[loong64] Port the RISC-V optimised TCP/IP checksum implementation
authorMichael Brown <mcb30@ipxe.org>
Sun, 24 May 2026 22:00:08 +0000 (23:00 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 26 May 2026 09:53:11 +0000 (10:53 +0100)
As with most other assembly code in iPXE, LoongArch64 is sufficiently
close to RISC-V that a straightforward transcription of the assembly
language code generally works.

Copy the RISC-V implementation for TCP/IP checksumming, retain the
register names and ABI, and just adjust the syntax to match
LoongArch64 requirements.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/loong64/core/loong64_tcpip.S [new file with mode: 0644]
src/arch/loong64/include/bits/tcpip.h [new file with mode: 0644]

diff --git a/src/arch/loong64/core/loong64_tcpip.S b/src/arch/loong64/core/loong64_tcpip.S
new file mode 100644 (file)
index 0000000..4111a06
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+       FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+       FILE_SECBOOT ( PERMITTED )
+
+/** @file
+ *
+ * TCP/IP checksum
+ *
+ */
+
+       .section ".note.GNU-stack", "", @progbits
+       .text
+
+/**
+ * Calculate continued TCP/IP checkum
+ *
+ * @v partial          Checksum of already-summed data, in network byte order
+ * @v data             Data buffer
+ * @v len              Length of data buffer
+ * @ret cksum          Updated checksum, in network byte order
+ *
+ * In practice, this routine will only ever be called with a data
+ * pointer aligned to a 16-bit boundary.  We optimise for this case,
+ * ensuring that the code would still give correct output if called
+ * with a misaligned pointer.
+ */
+       .section ".text.tcpip_continue_chksum", "ax", @progbits
+       .globl  tcpip_continue_chksum
+tcpip_continue_chksum:
+
+       /* Set up register usage:
+        *
+        * a0: checksum low 64 bits
+        * a1: data pointer
+        * a2: end of data pointer
+        * a3: end of data pointer minus a constant offset of interest
+        * a4: checksum high bits (guaranteed to never carry)
+        * a5: temporary register
+        */
+       nor     $a0, $a0, $zero
+       add.d   $a2, $a2, $a1
+       addi.d  $a3, $a2, -8
+       move    $a4, $zero
+
+       /* Skip aligned checksumming if data is too short */
+       bgtu    $a1, $a3, post_aligned
+
+       /* Checksum 16-bit words until we reach 64-bit alignment (or
+        * one byte past 64-bit alignment).
+        */
+       b       2f
+1:     ld.hu   $a5, $a1, 0
+       addi.d  $a1, $a1, 2
+       add.d   $a4, $a4, $a5
+2:     andi    $a5, $a1, ( ( 8 - 1 ) & ~1 )
+       bnez    $a5, 1b
+
+       /* Checksum aligned 64-bit words */
+       b       2f
+1:     ld.d    $a5, $a1, 0
+       addi.d  $a1, $a1, 8
+       add.d   $a0, $a0, $a5
+       sltu    $a5, $a0, $a5
+       add.d   $a4, $a4, $a5
+2:     bleu    $a1, $a3, 1b
+
+post_aligned:
+       /* Checksum remaining 16-bit words */
+       addi.d  $a3, $a2, -2
+       b       2f
+1:     ld.hu   $a5, $a1, 0
+       addi.d  $a1, $a1, 2
+       add.d   $a4, $a4, $a5
+2:     bleu    $a1, $a3, 1b
+
+       /* Checksum final byte if present */
+       beq     $a1, $a2, 1f
+       ld.bu   $a5, $a1, 0
+       add.d   $a4, $a4, $a5
+1:
+       /* Fold down to 64 bits */
+       add.d   $a0, $a0, $a4
+       sltu    $a4, $a0, $a4
+       add.d   $a0, $a0, $a4
+
+       /* Fold down to (high) 32 bits */
+       slli.d  $a4, $a0, 32
+       add.d   $a0, $a0, $a4
+       sltu    $a4, $a0, $a4
+       slli.d  $a4, $a4, 32
+       add.d   $a0, $a0, $a4
+
+       /* Fold down to (high) 16 bits */
+       srli.d  $a4, $a0, 32
+       slli.d  $a4, $a4, 48
+       add.d   $a0, $a0, $a4
+       sltu    $a4, $a0, $a4
+       slli.d  $a4, $a4, 48
+       add.d   $a0, $a0, $a4
+
+       /* Negate, move to low bits, and return */
+       nor     $a0, $a0, $zero
+       srli.d  $a0, $a0, 48
+       ret
+       .size   tcpip_continue_chksum, . - tcpip_continue_chksum
diff --git a/src/arch/loong64/include/bits/tcpip.h b/src/arch/loong64/include/bits/tcpip.h
new file mode 100644 (file)
index 0000000..52d0324
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _BITS_TCPIP_H
+#define _BITS_TCPIP_H
+
+/** @file
+ *
+ * Transport-network layer interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
+
+extern uint16_t tcpip_continue_chksum ( uint16_t partial, const void *data,
+                                       size_t len );
+
+#endif /* _BITS_TCPIP_H */