[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC] post-processing tool
From: |
Hollis Blanchard |
Subject: |
[RFC] post-processing tool |
Date: |
Sun, 3 Oct 2004 22:40:17 -0500 (CDT) |
The CHRP binding for IEEE 1275 says that ELF files loaded by firmware must
have a special PT_NOTE segment (segment, not section). [Aside: if Apple
firmware ever sees this NOTE, it renders itself unbootable.]
objcopy doesn't do segments, only sections. A linker script *could* do
what we need, but in order to use the PHDRS statement, it seems we would
need to write an entire linker script (which I would rather not do).
Linux uses a post-processing tool called addnote to add the NOTE segment
to a normal ELF file. I have written my own version of that, which I'm
calling "appendnote" to avoid confusion. If it goes into GRUB, it probably
belongs in a util/powerpc/ieee1275 directory.
I don't believe there exists a grub-setup for PPC, but this could warrant
it. One could run grub-setup on the target machine, which could be a shell
script that does the following:
- if the system is Old World Mac, install stage1 with a block list for
grubof
- if CHRP, run appendnote on grubof
- if CHRP or New World:
- find the OF device path to grubof (like ybin or SUSE's "lilo" script)
- use nvsetenv to point firmware to grubof
In that model, appendnote would be a tool compiled and installed on the
target. The alternative is to create grubof and grubof.chrp at compile
time, install both on the target, and let grub-setup point OF at one or
the other.
Any comments? How do I add this tool to the Makefiles?
-Hollis
/* appendnote.c -- add an IEEE 1275 CHRP NOTE segment to an ELF file. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <grub/elf.h>
#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1))
struct chrp_note {
Elf32_Nhdr header;
unsigned char name[8];
uint32_t real_mode;
uint32_t real_base;
uint32_t real_size;
uint32_t virt_base;
uint32_t virt_size;
uint32_t load_base;
};
off_t segtable_size(void *file)
{
Elf32_Ehdr *elf_header = (Elf32_Ehdr *)file;
return elf_header->e_phentsize * elf_header->e_phnum;
}
int modify_elf(void *infile, off_t infile_size, void *outfile)
{
Elf32_Ehdr *orig_elf_header = (Elf32_Ehdr *)infile;
Elf32_Ehdr *new_elf_header = (Elf32_Ehdr *)outfile;
Elf32_Phdr *note_pheader;
struct chrp_note *note;
char arch[] = "PowerPC";
/* copy whole file */
memcpy(outfile, infile, infile_size);
/* copy the old segment table to the end of the file */
memcpy((uint8_t *)outfile + infile_size,
(uint8_t *)infile + orig_elf_header->e_phoff,
segtable_size(infile));
new_elf_header->e_phoff = infile_size;
/* calculate NOTE program header location */
note_pheader = (Elf32_Phdr *)((uint8_t *)outfile + infile_size);
note_pheader += new_elf_header->e_phnum; /* skip existing headers */
new_elf_header->e_phnum++; /* and now there is one more */
memset(note_pheader, 0, new_elf_header->e_phentsize);
note_pheader->p_type = PT_NOTE;
note_pheader->p_offset = new_elf_header->e_phoff +
segtable_size(outfile);
note_pheader->p_filesz = sizeof(struct chrp_note);
/* now add the NOTE data */
note = (struct chrp_note *)(note_pheader + 1);
note->header.n_namesz = strlen(arch) + 1;
note->header.n_descsz = sizeof(struct chrp_note);
note->header.n_type = 0x1275;
strcpy(note->name, arch);
note->real_mode = 0xffffffff;
note->real_base = 0x00c00000;
note->real_size = 0xffffffff;
note->virt_base = 0xffffffff;
note->virt_size = 0xffffffff;
note->load_base = 0x00004000;
return 0;
}
int append_size(void *infile)
{
Elf32_Ehdr *elf_header = (Elf32_Ehdr *)infile;
return elf_header->e_phentsize * (elf_header->e_phnum + 1)
+ sizeof(struct chrp_note);
}
int is_elf (void *file)
{
Elf32_Ehdr *elf_header = (Elf32_Ehdr *)file;
if (memcmp (elf_header->e_ident, ELFMAG, SELFMAG))
return 0;
return 1;
}
void *open_infile(char *path, off_t size)
{
void *file;
int fd;
fd = open(path, O_RDONLY);
if (fd == -1) {
perror("open");
return NULL;
}
file = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
close(fd);
if (file == MAP_FAILED) {
perror("mmap");
return NULL;
}
return file;
}
void *open_outfile(char *path, off_t size)
{
void *file;
int fd;
fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
perror("open");
return NULL;
}
if (ftruncate(fd, size) == -1) {
perror("ftruncate");
return NULL;
}
file = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (file == MAP_FAILED) {
perror("mmap");
return NULL;
}
return file;
}
int main (int argc, char *argv[])
{
struct stat instat;
void *infile;
void *outfile;
off_t aligned_size;
if (argc < 3) {
fprintf (stderr, "Usage: %s <ELF file> <new ELF file>\n",
argv[0]);
return 1;
}
if (stat(argv[1], &instat) == -1) {
perror("stat");
return 1;
}
aligned_size = ALIGN_UP(instat.st_size, 4);
infile = open_infile(argv[1], aligned_size);
if (infile == NULL) {
fprintf (stderr, "Couldn't open %s\n", argv[1]);
return 1;
}
outfile = open_outfile(argv[2], aligned_size + append_size(infile));
if (outfile == NULL) {
fprintf (stderr, "Couldn't open %s\n", argv[2]);
return 1;
}
if (!is_elf(infile)) {
fprintf (stderr, "%s: not an ELF file\n", argv[1]);
return 1;
}
modify_elf(infile, aligned_size, outfile);
return 0;
}
- [RFC] post-processing tool,
Hollis Blanchard <=