Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*	$NetBSD: iplsum.c,v 1.2 2015/12/13 18:38:23 christos Exp $	*/

/*
 * Calculate 32bit checksum of IPL and store in a certain location
 *
 * Written in 2003 by ITOH Yasufumi.
 * Public domain
 */

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#ifndef __BIT_TYPES_DEFINED__
typedef unsigned int	uint32_t;
#endif

/* see README.ipl */
#define IPLOFF		(4*1024)	/* 4KB */
#define IPL1SIZE	(4*1024)	/* 4KB */
#define IPL2SIZE	(1*1024)	/* 1KB */
#define IPL2ONDISK	0x0400
#define IPL3SIZE	(3*512)		/* 1.5KB */
#define IPL3ONDISK	0x0A00
#define IPLSIZE		(IPL1SIZE + IPL2SIZE + IPL3SIZE)
#define BOOTSIZE	(IPLOFF + IPLSIZE)
#define BOOTBLOCKSIZE	8192

uint32_t bootblk[BOOTSIZE / sizeof(uint32_t) + 1];

#define SUMOFF		((IPLOFF + 4) / sizeof(uint32_t))

#ifdef __STDC__
int main(int, char *[]);
#endif

int
main(int argc, char *argv[])
{
	FILE *fp;
	int len;
	uint32_t sum, *p;
	int iploff, iplsumsize;

	if (argc != 3) {
		fprintf(stderr, "usage: %s <input> <output>\n", argv[0]);
		return 1;
	}

	/* read file */
	if ((fp = fopen(argv[1], "rb")) == NULL) {
		perror(argv[1]);
		return 1;
	}
	if ((len = fread(bootblk, 1, sizeof bootblk, fp)) <= IPLOFF) {
		fclose(fp);
		fprintf(stderr, "%s: too short\n", argv[1]);
		return 1;
	} else if (len > BOOTSIZE) {
		fclose(fp);
		fprintf(stderr, "%s: too long (%d vs %d)\n", argv[1], len, BOOTSIZE);
		return 1;
	}
	(void) fclose(fp);

	/* sanity check */
	if ((ntohl(bootblk[0]) & 0xffff0000) != 0x80000000) {
		fprintf(stderr, "%s: bad LIF magic\n", argv[1]);
		return 1;
	}
	iploff = ntohl(bootblk[0xf0 / sizeof(uint32_t)]);
	iplsumsize = ntohl(bootblk[0xf4 / sizeof(uint32_t)]);
	printf("%d bytes free, ipl offset = %d, ipl sum size = %d\n",
	    BOOTSIZE - len, iploff, iplsumsize);
	if (iploff != IPLOFF || iplsumsize <= 0 || iplsumsize % 2048 ||
	    iploff + iplsumsize > BOOTBLOCKSIZE) {
		fprintf(stderr, "%s: bad ipl offset / size\n", argv[1]);
		return 1;
	}

	/* checksum */
	sum = 0;
	for (p = bootblk + IPLOFF / sizeof(uint32_t);
	    p < bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t); p++)
		sum += ntohl(*p);

	bootblk[SUMOFF] = htonl(ntohl(bootblk[SUMOFF]) - sum);

	/* transfer ipl part 2 */
	memcpy(bootblk + IPL2ONDISK / sizeof(uint32_t),
	    bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t),
	    IPL2SIZE);

	/* transfer ipl part 3 */
	memcpy(bootblk + IPL3ONDISK / sizeof(uint32_t),
	    bootblk + (IPLOFF + IPL1SIZE + IPL2SIZE) / sizeof(uint32_t),
	    IPL3SIZE);

	/* write file */
	if ((fp = fopen(argv[2], "wb")) == NULL) {
		perror(argv[2]);
		return 1;
	}
	if ((len = fwrite(bootblk, 1, BOOTBLOCKSIZE, fp)) != BOOTBLOCKSIZE) {
		if (len < 0)
			perror(argv[2]);
		else
			fprintf(stderr, "%s: short write\n", argv[2]);
		fclose(fp);
		(void) remove(argv[2]);
		return 1;
	}
	if (fclose(fp)) {
		perror(argv[2]);
		(void) remove(argv[2]);
		return 1;
	}

	return 0;
}