Use fast memset in SMM mode, too
[coreboot.git] / src / lib / compute_ip_checksum.c
1 #include <stdint.h>
2 #include <ip_checksum.h>
3
4 unsigned long compute_ip_checksum(void *addr, unsigned long length)
5 {
6         uint8_t *ptr;
7         volatile union {
8                 uint8_t  byte[2];
9                 uint16_t word;
10         } value;
11         unsigned long sum;
12         unsigned long i;
13         /* In the most straight forward way possible,
14          * compute an ip style checksum.
15          */
16         sum = 0;
17         ptr = addr;
18         for(i = 0; i < length; i++) {
19                 unsigned long v;
20                 v = ptr[i];
21                 if (i & 1) {
22                         v <<= 8;
23                 }
24                 /* Add the new value */
25                 sum += v;
26                 /* Wrap around the carry */
27                 if (sum > 0xFFFF) {
28                         sum = (sum + (sum >> 16)) & 0xFFFF;
29                 }
30         }
31         value.byte[0] = sum & 0xff;
32         value.byte[1] = (sum >> 8) & 0xff;
33         return (~value.word) & 0xFFFF;
34 }
35
36 unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
37 {
38         unsigned long checksum;
39         sum = ~sum & 0xFFFF;
40         new = ~new & 0xFFFF;
41         if (offset & 1) {
42                 /* byte swap the sum if it came from an odd offset
43                  * since the computation is endian independant this
44                  * works.
45                  */
46                 new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
47         }
48         checksum = sum + new;
49         if (checksum > 0xFFFF) {
50                 checksum -= 0xFFFF;
51         }
52         return (~checksum) & 0xFFFF;
53 }