lib: Move IP checksum to commonlib

This patch moves the IP checksum algorithm into commonlib to prepare for
it being shared with libpayload. The current implementation is ancient
and pretty hard to read (and does some unnecessary questionable things
like the type-punning stuff which leads to suboptimal code generation),
so this reimplements it from scratch (that also helps with the
licensing).

This algorithm is prepared to take in a pre-calculated "wide" checksum
in a machine-register-sized data type which is then narrowed down to 16
bits (see RFC 1071 for why that's valid). This isn't used yet (and the
code will get optimized out), but will be used later in this patch
series for architecture-specific optimization.

Change-Id: Ic04c714c00439a17fc04a8a6e730cc2aa19b8e68
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/80251
Reviewed-by: Yidi Lin <yidilin@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Jakub Czapiga <czapiga@google.com>
This commit is contained in:
Julius Werner
2024-01-30 16:51:05 -08:00
parent 416cc66592
commit de37109767
23 changed files with 119 additions and 128 deletions

View File

@@ -116,8 +116,6 @@ ramstage-y += rtc.c
romstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
romstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c
bootblock-y += compute_ip_checksum.c
romstage-y += compute_ip_checksum.c
romstage-y += dimm_info_util.c
ifeq ($(CONFIG_COMPILER_GCC),y)
bootblock-$(CONFIG_ARCH_BOOTBLOCK_X86_32) += gcc.c
@@ -145,7 +143,6 @@ ramstage-y += malloc.c
ramstage-y += dimm_info_util.c
ramstage-y += delay.c
ramstage-y += fallback_boot.c
ramstage-y += compute_ip_checksum.c
ramstage-y += cbfs.c
ramstage-y += lzma.c lzmadecode.c
ramstage-y += stack.c

View File

@@ -1,53 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdint.h>
#include <ip_checksum.h>
unsigned long compute_ip_checksum(const void *addr, unsigned long length)
{
const uint8_t *ptr;
volatile union {
uint8_t byte[2];
uint16_t word;
} value;
unsigned long sum;
unsigned long i;
/* In the most straight forward way possible,
* compute an ip style checksum.
*/
sum = 0;
ptr = addr;
for (i = 0; i < length; i++) {
unsigned long v;
v = ptr[i];
if (i & 1)
v <<= 8;
/* Add the new value */
sum += v;
/* Wrap around the carry */
if (sum > 0xFFFF)
sum = (sum + (sum >> 16)) & 0xFFFF;
}
value.byte[0] = sum & 0xff;
value.byte[1] = (sum >> 8) & 0xff;
return (~value.word) & 0xFFFF;
}
unsigned long add_ip_checksums(unsigned long offset, unsigned long sum,
unsigned long new)
{
unsigned long checksum;
sum = ~sum & 0xFFFF;
new = ~new & 0xFFFF;
if (offset & 1) {
/* byte swap the sum if it came from an odd offset
* since the computation is endian independent this
* works.
*/
new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
}
checksum = sum + new;
if (checksum > 0xFFFF)
checksum -= 0xFFFF;
return (~checksum) & 0xFFFF;
}

View File

@@ -2,10 +2,10 @@
#include <acpi/acpi.h>
#include <arch/cbconfig.h>
#include <commonlib/bsd/ipchksum.h>
#include <console/console.h>
#include <console/uart.h>
#include <identity.h>
#include <ip_checksum.h>
#include <boot/coreboot_tables.h>
#include <boot/tables.h>
#include <boot_device.h>
@@ -432,10 +432,9 @@ static unsigned long lb_table_fini(struct lb_header *head)
}
first_rec = lb_first_record(head);
head->table_checksum = compute_ip_checksum(first_rec,
head->table_bytes);
head->table_checksum = ipchksum(first_rec, head->table_bytes);
head->header_checksum = 0;
head->header_checksum = compute_ip_checksum(head, sizeof(*head));
head->header_checksum = ipchksum(head, sizeof(*head));
printk(BIOS_DEBUG,
"Wrote coreboot table at: %p, 0x%x bytes, checksum %x\n",
head, head->table_bytes, head->table_checksum);