oskit/oskit-20020317/boot/linux/mklinux2.in

221 lines
6.6 KiB
Plaintext
Executable File

#!@PERL@
#
# Copyright (c) 1994-1996, 1998-2000 University of Utah and the Flux Group.
# All rights reserved.
#
# This file is part of the Flux OSKit. The OSKit is free software, also known
# as "open source;" you can redistribute it and/or modify it under the terms
# of the GNU General Public License (GPL), version 2, as published by the Free
# Software Foundation (FSF). To explore alternate licensing terms, contact
# the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
#
# The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
# received a copy of the GPL along with the OSKit; see the file COPYING. If
# not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
#
# This little script uses GNU ld to build a Linux 16-bit compressed boot image
# from a set of boot modules.
#
# Usage: mklinux2 [options] [files ...]
#
# Options:
# -x filename
# Use <filename> as the MultiBoot adaptor file instead of the default.
# -o filename
# Specify the output <filename> of the resulting Linux image. The
# default is "zImage" in the current directory.
# -c 'string'
# Specify a command line <string> to pass to the kernel when it is
# invoked.
# -stdin
# Take file specifications from stdin, in addition to those on the
# command line. This is useful when using another script to build
# a list of file specifications which can then be piped into this
# script.
# -save-temps
# Debugging option to save temporary files instead of deleting them
# after the image is built.
# [files ...]
# A list of file specifications in the format pathname1:pathname2,
# where pathname1 is the name of a local module which is placed in the
# boot image. If :pathname2 is provided, it specifies the name to give
# the module in the image. If :pathname2 is omitted, it defaults to
# pathname1.
#
# The first file specification is typically the name of the Oskit kernel.
#
$bootdir = $ENV{"BOOTDIR"};
$cc = $ENV{"CC"};
$ld = $ENV{"LD"};
if (!$cc) { $cc = "@CC@"; }
if (!$ld) { $ld = "@LD@"; }
if (!$bootdir) { $bootdir = "@prefix@/lib/boot"; }
$bb="$bootdir/linuxboot.bin";
@modules = ();
$outfile="zImage";
$savetemps=0;
$fromstdin = 0;
$ldopts="-Ttext 0 -defsym _start=0 -oformat binary";
$cmdlinefile="bootadapter_cmdline";
$def_syssize = 0x7f00;
$def_setupssecs = 4;
if ($#ARGV == -1) {
print "Usage: mklinux2 [option | filename]\n";
exit;
}
# Parse the command-line options
while ($#ARGV >= 0) {
if ($ARGV[0] eq "-x") { $bb = $ARGV[1]; shift @ARGV; }
elsif ($ARGV[0] eq "-o") { $outfile = $ARGV[1]; shift @ARGV; }
elsif ($ARGV[0] eq "-c") { $cmdline = $ARGV[1]; shift @ARGV; }
elsif ($ARGV[0] eq "-stdin") { $fromstdin = 1; }
elsif ($ARGV[0] eq "-save-temps") { $savetemps = 1; }
else { push(@modules, $ARGV[0]); }
shift @ARGV;
}
# Add in anything from stdin if they've asked for it.
if ($fromstdin) {
while (<STDIN>) {
@words = split;
push(@modules, @words);
}
}
# Link in the command line if they specified one
if ($cmdline) {
open(CMD, ">$outfile.cmdline") ||
die "could not open cmdline file: $!\n";
print CMD "$cmdline\n";
push(@modules, "${outfile}.cmdline:${cmdlinefile}");
close(CMD);
}
open(OUT, ">${outfile}.mods.S") || die "Could not open outfile: $!\n";
@files = ();
@linksmade = ();
# Wrap each of the input files in a .o file.
# At the same time, build an assembly language module
# containing a table describing the boot modules.
print OUT ".text; .long 0xf00baabb\n";
foreach $module (@modules) {
$file = $module;
$file =~ s/:.*$//;
$string = $module;
$string =~ s/^[^:]*://;
if (!length($string)) { $string = $file; }
if (!$FOUND{$file}) { # Must be unique or we get linker probs
push(@files, $file); #This is where the shell script bogged down
}
$FOUND{$file} = 1;
# Convert all non alphanumeric characters to underscores.
# The BFD binary input format will do the same thing
# to produce the symbol names that it wraps around the input files
$sym_name = $file;
$sym_name =~ s/[^a-zA-Z0-9]/_/g;
print OUT<<EOL;
.long _binary_${sym_name}_start
.long _binary_${sym_name}_end
.long cmdline_${sym_name}
.data
cmdline_${sym_name}: .ascii "${string}\\0"
.text
EOL
}
print OUT ".long 0; .data; .align 4\n";
close(OUT);
# Turn the assembly discription module into a .o
$res = system("${cc} -c -o ${outfile}.mods.o ${outfile}.mods.S");
if ($res) {
&cleanup();
die "FATAL: C compiler ($cc) failed\n";
}
# Parse the file list, doing any necessary magic to the files.
# I'm leaving this in for now for experimentation with different
# linker args to try to get library files to load properly.
$filelist = "";
foreach $file (@files) {
## Escape any '$' that occur in file names (happens a lot with Java classes)
$file =~ s/\$/\\\$/g;
$filelist .= "$file ";
}
# Link the module vector file with the boot module files.
# Use the binary bfd backend for both the input bmod files and the output file.
# There is no meaning to "entry point address" in the binary backend,
# but the linker doesn't know that, so it looks for _start and warns
# when it doesn't find it (and falls back to zero). To stifle the warning
# we can define the `_start' symbol on the command line; I think this
# works with all GNU ld versions.
$res = system("$ld $ldopts -o $outfile.tmp $outfile.mods.o -format binary $filelist -format default");
if ($res) {
&cleanup();
die "FATAL: linker ($ld) failed: $res\n";
}
# Compress the whole output file as one big glob.
$res = system("gzip -9 <$outfile.tmp >$outfile.tmp.gz");
if ($res) {
&cleanup();
die "FATAL: gzip failed: $res\n";
}
# Create the final boot image by tacking that onto the end of 'linuxboot.bin'.
$res = system("cat $bootdir/linuxboot.bin $outfile.tmp.gz >$outfile");
if ($res) {
&cleanup();
die "FATAL: final cat failed: $res\n";
}
# Update the system size in the boot image, so we only load as much
# as we need, not DEF_SYSSIZE
open(OUT, "+< ${outfile}") || die "Couldn't open $outfile.\n";
$size = (stat OUT)[7];
$sys_size = ($size + 15) / 16;
if ($sys_size > $def_syssize) {
print "System size is too big!\n";
}
seek(OUT, 500, 0) || die "Couldn't seek to SYS_SIZE offset.\n";
$buf = pack("v", $sys_size);
(syswrite(OUT, $buf, 2) == 2) || die "Couldn't write system size!\n";
close OUT;
# Nuke our temp files, unless asked not to.
if (!$savetemps) {
system("rm -f $outfile.mods.S $outfile.mods.o ${outfile}.cmdline $outfile.tmp*");
}
exit(0);
# A stub if we need to do any cleanup on failure.
sub cleanup {
;
}