aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/boot/addinitrd.c
blob: b5b3febc10cc9d12a8ddd9ef01aaf022711b7198 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * addinitrd - program to add a initrd image to an ecoff kernel
 *
 * (C) 1999 Thomas Bogendoerfer
 * minor modifications, cleanup: Guido Guenther <agx@sigxcpu.org>
 * further cleanup: Maciej W. Rozycki
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>

#include "ecoff.h"

#define MIPS_PAGE_SIZE	4096
#define MIPS_PAGE_MASK	(MIPS_PAGE_SIZE-1)

#define swab16(x) \
        ((unsigned short)( \
                (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \
                (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) ))

#define swab32(x) \
        ((unsigned int)( \
                (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
                (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
                (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
                (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))

#define SWAB(a)	(swab ? swab32(a) : (a))

void die(char *s)
{
	perror(s);
	exit(1);
}

int main(int argc, char *argv[])
{
	int fd_vmlinux, fd_initrd, fd_outfile;
	FILHDR efile;
	AOUTHDR eaout;
	SCNHDR esecs[3];
	struct stat st;
	char buf[1024];
	unsigned long loadaddr;
	unsigned long initrd_header[2];
	int i, cnt;
	int swab = 0;

	if (argc != 4) {
		printf("Usage: %s <vmlinux> <initrd> <outfile>\n", argv[0]);
		exit(1);
	}

	if ((fd_vmlinux = open (argv[1], O_RDONLY)) < 0)
		 die("open vmlinux");
	if (read (fd_vmlinux, &efile, sizeof efile) != sizeof efile)
		die("read file header");
	if (read (fd_vmlinux, &eaout, sizeof eaout) != sizeof eaout)
		die("read aout header");
	if (read (fd_vmlinux, esecs, sizeof esecs) != sizeof esecs)
		die("read section headers");
	/*
	 * check whether the file is good for us
	 */
	/* TBD */

	/*
	 * check, if we have to swab words
	 */
	if (ntohs(0xaa55) == 0xaa55) {
		if (efile.f_magic == swab16(MIPSELMAGIC))
			swab = 1;
	} else {
		if (efile.f_magic == swab16(MIPSEBMAGIC))
			swab = 1;
	}

	/* make sure we have an empty data segment for the initrd */
	if (eaout.dsize || esecs[1].s_size) {
		fprintf(stderr, "Data segment not empty. Giving up!\n");
		exit(1);
	}
	if ((fd_initrd = open (argv[2], O_RDONLY)) < 0)
		die("open initrd");
	if (fstat (fd_initrd, &st) < 0)
		die("fstat initrd");
	loadaddr = ((SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size)
			+ MIPS_PAGE_SIZE-1) & ~MIPS_PAGE_MASK) - 8;
	if (loadaddr < (SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size)))
		loadaddr += MIPS_PAGE_SIZE;
	initrd_header[0] = SWAB(0x494E5244);
	initrd_header[1] = SWAB(st.st_size);
	eaout.dsize = esecs[1].s_size = initrd_header[1] = SWAB(st.st_size+8);
	eaout.data_start = esecs[1].s_vaddr = esecs[1].s_paddr = SWAB(loadaddr);

	if ((fd_outfile = open (argv[3], O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
		die("open outfile");
	if (write (fd_outfile, &efile, sizeof efile) != sizeof efile)
		die("write file header");
	if (write (fd_outfile, &eaout, sizeof eaout) != sizeof eaout)
		die("write aout header");
	if (write (fd_outfile, esecs, sizeof esecs) != sizeof esecs)
		die("write section headers");
	/* skip padding */
	if(lseek(fd_vmlinux, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1)
		die("lseek vmlinux");
	if(lseek(fd_outfile, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1)
		die("lseek outfile");
	/* copy text segment */
	cnt = SWAB(eaout.tsize);
	while (cnt) {
		if ((i = read (fd_vmlinux, buf, sizeof buf)) <= 0)
			die("read vmlinux");
		if (write (fd_outfile, buf, i) != i)
			die("write vmlinux");
		cnt -= i;
	}
	if (write (fd_outfile, initrd_header, sizeof initrd_header) != sizeof initrd_header)
		die("write initrd header");
	while ((i = read (fd_initrd, buf, sizeof buf)) > 0)
		if (write (fd_outfile, buf, i) != i)
			die("write initrd");
	close(fd_vmlinux);
	close(fd_initrd);
	return 0;
}