grub-devel
[Top][All Lists]
Advanced

[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;
}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]