blob: 30eaef4c2868520aa87c6acebe22ea9859896f4a [file] [log] [blame]
/*
Jan Vondrak (C) 1998
Jakub Jelinek (C) 1998
A simple program which appends the kernel and root images
to the boot loader and patches the addresses in its image_table[]
Parameters:
kernel4=<filename>
kernel4c=<filename>
kernel4u=<filename>
... compressed kernel images (in a.out format)
size4=<bytes>
size4c=<bytes>
size4u=<bytes>
... original sizes of kernel images (uncompressed)
root4=<addr>
root4c=<addr>
root4u=<addr>
... virtual address of root image for each kernel (in hex)
root=<filename>
... compressed root image
out=<filename>
... the output file
*/
#include <stdio.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include "b.h"
#include "b2.h"
#define MAX_BOOT_LEN 0x400000
char output_buffer[MAX_BOOT_LEN];
struct ImageInfo {
unsigned packed_start;
unsigned packed_len;
unsigned unpacked_len;
unsigned root_start;
};
int root_tweak (char *s)
{
unsigned p;
p = strtoul (s, NULL, 16); /* read virtual address in hex */
return p ? (p + 32 + 0x1fff) & ~0x1fff : 0; /* add 32 bytes and round to 8 KB */
}
int main (int argc, char **argv)
{
int i,len,rootlen;
FILE *f, *g = NULL;
struct ImageInfo *ii;
char *sun4_kernel_start;
char *sun4c_kernel_start;
char *sun4u_kernel_start;
char *root_image_start;
char *output_end;
int sun4_size = 0, sun4_root = 0;
int sun4c_size = 0, sun4c_root = 0;
int sun4u_size = 0, sun4u_root = 0;
char *sun4_kernel = 0;
char *sun4c_kernel = 0;
char *sun4u_kernel = 0;
char *root_image = 0;
char *output_file = 0;
if (argc < 4) {
fprintf (stderr, "Usage: maketilo\n"
"\tsun4=<sun4 gzipped kernel> size4=<sun4 orig size> root4=<sun4 root address>\n"
"\tsun4c=<sun4c gzipped size> size4c=<sun4c orig size> root4c=<sun4c root address>\n"
"\tsun4u=<sun4u gzipped kernel> size4u=<sun4u orig size> root4u=<sun4u root address>\n"
"\troot=<root image>\n"
"\tout=<output file>\n");
return -1;
}
for (i=1;i<argc;i++) {
if (!strncmp (argv[i], "sun4=", 5))
sun4_kernel = argv[i] + 5;
else if (!strncmp (argv[i], "sun4c=", 6))
sun4c_kernel = argv[i] + 6;
else if (!strncmp (argv[i], "sun4u=", 6))
sun4u_kernel = argv[i] + 6;
else if (!strncmp (argv[i], "size4=", 6))
sun4_size = atoi (argv[i]+6);
else if (!strncmp (argv[i], "size4c=", 7))
sun4c_size = atoi (argv[i]+7);
else if (!strncmp (argv[i], "size4u=", 7))
sun4u_size = atoi (argv[i]+7);
else if (!strncmp (argv[i], "root4=", 6))
sun4_root = root_tweak (argv[i]+6);
else if (!strncmp (argv[i], "root4c=", 7))
sun4c_root = root_tweak (argv[i]+7);
else if (!strncmp (argv[i], "root4u=", 7))
sun4u_root = root_tweak (argv[i]+7);
else if (!strncmp (argv[i], "root=", 5))
root_image = argv[i] + 5;
else if (!strncmp (argv[i], "out=", 4))
output_file = argv[i] + 4;
}
if (!sun4_kernel) {
/*fprintf (stderr, "WARNING: Kernel for Sun4 not specified\n");*/
} else if (!sun4_size || (!sun4_root && root_image)) {
fprintf (stderr, "WARNING: Original size and root address must be specified for Sun4\n");
return -1;
}
if (!sun4c_kernel) {
fprintf (stderr, "WARNING: Kernel for Sun4c/m/d not specified\n");
} else if (!sun4c_size || (!sun4c_root && root_image)) {
fprintf (stderr, "ERROR: Original size and root address must be specified for Sun4c\n");
return -1;
}
if (!sun4u_kernel) {
fprintf (stderr, "WARNING: Kernel for Sun4u not specified\n");
} else if (!sun4u_size || (!sun4u_root && root_image)) {
fprintf (stderr, "ERROR: Original size and root address must be specified for Sun4u\n");
return -1;
}
if (!root_image && (sun4_root || sun4c_root || sun4u_root)) {
fprintf (stderr, "ERROR: Root image not specified\n");
return -1;
}
if (!output_file) {
fprintf (stderr, "ERROR: Output file not specified\n");
return -1;
}
if (root_image) {
g = fopen (root_image, "rb");
if (!g) {
fprintf (stderr, "Can't load %s\n", root_image);
return -1;
}
fseek (g, 0, SEEK_END);
rootlen = ftell (g);
fseek (g, 0, SEEK_SET);
} else {
rootlen = 0;
}
if (rootlen + sun4_size + 0x4000 + 0x10000 >= 0x330000 ||
rootlen + sun4c_size + 0x4000 + 0x10000 >= 0x330000 ||
rootlen + sun4u_size + 0x4000 + 0x10000 >= 0x330000) {
printf("Images are large. Will load on machines with at least 5M mapped by PROM only\n");
for (i=0; i<LARGE_BOOT_LEN; i++)
output_buffer[i] = large_boot_loader[i];
} else
for (i=0; i<BOOT_LEN; i++)
output_buffer[i] = boot_loader[i];
sun4_kernel_start = output_buffer + BOOT_LEN;
if (sun4_kernel) {
f = fopen (sun4_kernel, "rb");
if (!f) {
fprintf (stderr, "Can't load %s\n", sun4_kernel);
return -1;
}
fseek (f, 0, SEEK_END);
len = ftell (f);
fseek (f, 0, SEEK_SET);
fread (sun4_kernel_start, 1, len, f);
fclose (f);
} else
len = 0;
sun4c_kernel_start = sun4_kernel_start + len;
if (sun4c_kernel) {
f = fopen (sun4c_kernel, "rb");
if (!f) {
fprintf (stderr, "Can't load %s\n", sun4c_kernel);
return -1;
}
fseek (f, 0, SEEK_END);
len = ftell (f);
fseek (f, 0, SEEK_SET);
fread (sun4c_kernel_start, 1, len, f);
fclose (f);
} else
len = 0;
sun4u_kernel_start = sun4c_kernel_start + len;
if (sun4u_kernel) {
f = fopen (sun4u_kernel, "rb");
if (!f) {
fprintf (stderr, "Can't load %s\n", sun4u_kernel);
return -1;
}
fseek (f, 0, SEEK_END);
len = ftell (f);
fseek (f, 0, SEEK_SET);
fread (sun4u_kernel_start, 1, len, f);
fclose (f);
} else
len = 0;
root_image_start = sun4u_kernel_start + len;
if (root_image) {
fread (root_image_start, 1, rootlen, g);
fclose (g);
}
output_end = root_image_start + rootlen;
/* patch code, data and BSS size in the .out header */
*(unsigned*)(output_buffer+4) = htonl(output_end - output_buffer);
*(unsigned*)(output_buffer+8) = 0;
*(unsigned*)(output_buffer+12) = 0;
/* fill image_table[] in the boot loader */
ii = (struct ImageInfo*)(output_buffer + 40);
if (sun4_kernel) {
ii[0].packed_start = sun4_kernel_start - output_buffer - 32;
ii[0].packed_len = sun4c_kernel_start - sun4_kernel_start;
ii[0].unpacked_len = sun4_size;
ii[0].root_start = sun4_root;
} else {
ii[0].packed_start = 0;
ii[0].packed_len = 0;
ii[0].unpacked_len = 0;
ii[0].root_start = 0;
}
if (sun4c_kernel) {
ii[1].packed_start = sun4c_kernel_start - output_buffer - 32;
ii[1].packed_len = sun4u_kernel_start - sun4c_kernel_start;
ii[1].unpacked_len = sun4c_size;
ii[1].root_start = sun4c_root;
} else {
ii[1].packed_start = 0;
ii[1].packed_len = 0;
ii[1].unpacked_len = 0;
ii[1].root_start = 0;
}
if (sun4u_kernel) {
ii[2].packed_start = sun4u_kernel_start - output_buffer - 32;
ii[2].packed_len = root_image_start - sun4u_kernel_start;
ii[2].unpacked_len = sun4u_size;
ii[2].root_start = sun4u_root;
} else {
ii[2].packed_start = 0;
ii[2].packed_len = 0;
ii[2].unpacked_len = 0;
ii[2].root_start = 0;
}
ii[3].packed_start = root_image_start - output_buffer - 32;
ii[3].packed_len = output_end - root_image_start;
ii[3].unpacked_len = 0;
ii[3].root_start = 0;
for (i = 0; i < 4; i++) {
ii[i].packed_start = htonl(ii[i].packed_start);
ii[i].packed_len = htonl(ii[i].packed_len);
ii[i].unpacked_len = htonl(ii[i].unpacked_len);
ii[i].root_start = htonl(ii[i].root_start);
}
f = fopen (output_file, "wb");
if (!f) {
fprintf (stderr, "Can't open %s for writing\n", output_file);
return -1;
}
fwrite (output_buffer, 1, output_end - output_buffer, f);
fclose (f);
return 0;
}