powerpc: Move ppc64 boot wrapper code over to arch/powerpc
This also extends the code to handle 32-bit ELF vmlinux files as well as 64-bit ones. This is sufficient for booting on new-world 32-bit powermacs (i.e. all recent machines). Signed-off-by: Paul Mackerras <paulus@samba.org>
此提交包含在:
149
arch/powerpc/boot/Makefile
一般檔案
149
arch/powerpc/boot/Makefile
一般檔案
@@ -0,0 +1,149 @@
|
||||
# Makefile for making ELF bootable images for booting on CHRP
|
||||
# using Open Firmware.
|
||||
#
|
||||
# Geert Uytterhoeven September 1997
|
||||
#
|
||||
# Based on coffboot by Paul Mackerras
|
||||
# Simplified for ppc64 by Todd Inglett
|
||||
#
|
||||
# NOTE: this code is built for 32 bit in ELF32 format even though
|
||||
# it packages a 64 bit kernel. We do this to simplify the
|
||||
# bootloader and increase compatibility with OpenFirmware.
|
||||
#
|
||||
# To this end we need to define BOOTCC, etc, as the tools
|
||||
# needed to build the 32 bit image. These are normally HOSTCC,
|
||||
# but may be a third compiler if, for example, you are cross
|
||||
# compiling from an intel box. Once the 64bit ppc gcc is
|
||||
# stable it will probably simply be a compiler switch to
|
||||
# compile for 32bit mode.
|
||||
# To make it easier to setup a cross compiler,
|
||||
# CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE
|
||||
# in the toplevel makefile.
|
||||
|
||||
|
||||
HOSTCC := gcc
|
||||
BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
|
||||
$(shell $(CROSS32CC) -print-file-name=include) -fPIC
|
||||
BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
|
||||
BOOTLFLAGS := -T $(srctree)/$(src)/zImage.lds
|
||||
OBJCOPYFLAGS := contents,alloc,load,readonly,data
|
||||
|
||||
zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
|
||||
zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
|
||||
zliblinuxheader := zlib.h zconf.h zutil.h
|
||||
|
||||
$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
|
||||
#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
|
||||
|
||||
src-boot := string.S prom.c main.c div64.S crt0.S
|
||||
src-boot += $(zlib)
|
||||
src-boot := $(addprefix $(obj)/, $(src-boot))
|
||||
obj-boot := $(addsuffix .o, $(basename $(src-boot)))
|
||||
|
||||
BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
|
||||
|
||||
quiet_cmd_copy_zlib = COPY $@
|
||||
cmd_copy_zlib = sed "s@__attribute_used__@@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
|
||||
|
||||
quiet_cmd_copy_zlibheader = COPY $@
|
||||
cmd_copy_zlibheader = sed "s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
|
||||
# stddef.h for NULL
|
||||
quiet_cmd_copy_zliblinuxheader = COPY $@
|
||||
cmd_copy_zliblinuxheader = sed "s@<linux/string.h>@\"string.h\"@;s@<linux/kernel.h>@<stddef.h>@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
|
||||
|
||||
$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
|
||||
$(call cmd,copy_zlib)
|
||||
|
||||
$(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
|
||||
$(call cmd,copy_zlibheader)
|
||||
|
||||
$(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
|
||||
$(call cmd,copy_zliblinuxheader)
|
||||
|
||||
clean-files := $(zlib) $(zlibheader) $(zliblinuxheader)
|
||||
|
||||
|
||||
quiet_cmd_bootcc = BOOTCC $@
|
||||
cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
|
||||
|
||||
quiet_cmd_bootas = BOOTAS $@
|
||||
cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
|
||||
|
||||
quiet_cmd_bootld = BOOTLD $@
|
||||
cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2)
|
||||
|
||||
$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
|
||||
$(call if_changed_dep,bootcc)
|
||||
$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
|
||||
$(call if_changed_dep,bootas)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# ELF sections within the zImage bootloader/wrapper
|
||||
#-----------------------------------------------------------
|
||||
required := vmlinux.strip
|
||||
initrd := initrd
|
||||
|
||||
obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section)))
|
||||
src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section)))
|
||||
gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section)))
|
||||
|
||||
hostprogs-y := addnote addRamDisk
|
||||
targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
|
||||
$(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
|
||||
$(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
|
||||
$(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
|
||||
vmlinux.initrd
|
||||
extra-y := initrd.o
|
||||
|
||||
quiet_cmd_ramdisk = RAMDISK $@
|
||||
cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@
|
||||
|
||||
quiet_cmd_stripvm = STRIP $@
|
||||
cmd_stripvm = $(STRIP) -s -R .comment $< -o $@
|
||||
|
||||
vmlinux.strip: vmlinux
|
||||
$(call if_changed,stripvm)
|
||||
$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz
|
||||
$(call if_changed,ramdisk)
|
||||
|
||||
quiet_cmd_addsection = ADDSEC $@
|
||||
cmd_addsection = $(CROSS32OBJCOPY) $@ \
|
||||
--add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \
|
||||
--set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS)
|
||||
|
||||
quiet_cmd_addnote = ADDNOTE $@
|
||||
cmd_addnote = $(obj)/addnote $@
|
||||
|
||||
$(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
|
||||
$(call if_changed,gzip)
|
||||
|
||||
$(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz
|
||||
cp -f $(obj)/ramdisk.image.gz $@
|
||||
|
||||
$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz
|
||||
@touch $@
|
||||
|
||||
$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
|
||||
$(call if_changed_dep,bootcc)
|
||||
$(call cmd,addsection)
|
||||
|
||||
$(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required))
|
||||
$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
|
||||
$(call cmd,bootld,$(obj-boot))
|
||||
|
||||
$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd))
|
||||
$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
|
||||
$(call cmd,bootld,$(obj-boot))
|
||||
|
||||
$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote
|
||||
@cp -f $< $@
|
||||
$(call if_changed,addnote)
|
||||
|
||||
$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
|
||||
@cp -f $< $@
|
||||
$(call if_changed,addnote)
|
||||
|
||||
install: $(CONFIGURE) $(BOOTIMAGE)
|
||||
sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
|
||||
|
||||
clean-files := $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
|
11
arch/powerpc/boot/README
一般檔案
11
arch/powerpc/boot/README
一般檔案
@@ -0,0 +1,11 @@
|
||||
|
||||
To extract the kernel vmlinux, System.map, .config or initrd from the zImage binary:
|
||||
|
||||
objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz
|
||||
objcopy -j .kernel:System.map -O binary zImage System.map.gz
|
||||
objcopy -j .kernel:.config -O binary zImage config.gz
|
||||
objcopy -j .kernel:initrd -O binary zImage.initrd initrd.gz
|
||||
|
||||
|
||||
Peter
|
||||
|
311
arch/powerpc/boot/addRamDisk.c
一般檔案
311
arch/powerpc/boot/addRamDisk.c
一般檔案
@@ -0,0 +1,311 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <elf.h>
|
||||
|
||||
#define ElfHeaderSize (64 * 1024)
|
||||
#define ElfPages (ElfHeaderSize / 4096)
|
||||
#define KERNELBASE (0xc000000000000000)
|
||||
#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
|
||||
|
||||
struct addr_range {
|
||||
unsigned long long addr;
|
||||
unsigned long memsize;
|
||||
unsigned long offset;
|
||||
};
|
||||
|
||||
static int check_elf64(void *p, int size, struct addr_range *r)
|
||||
{
|
||||
Elf64_Ehdr *elf64 = p;
|
||||
Elf64_Phdr *elf64ph;
|
||||
|
||||
if (elf64->e_ident[EI_MAG0] != ELFMAG0 ||
|
||||
elf64->e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
elf64->e_ident[EI_MAG2] != ELFMAG2 ||
|
||||
elf64->e_ident[EI_MAG3] != ELFMAG3 ||
|
||||
elf64->e_ident[EI_CLASS] != ELFCLASS64 ||
|
||||
elf64->e_ident[EI_DATA] != ELFDATA2MSB ||
|
||||
elf64->e_type != ET_EXEC || elf64->e_machine != EM_PPC64)
|
||||
return 0;
|
||||
|
||||
if ((elf64->e_phoff + sizeof(Elf64_Phdr)) > size)
|
||||
return 0;
|
||||
|
||||
elf64ph = (Elf64_Phdr *) ((unsigned long)elf64 +
|
||||
(unsigned long)elf64->e_phoff);
|
||||
|
||||
r->memsize = (unsigned long)elf64ph->p_memsz;
|
||||
r->offset = (unsigned long)elf64ph->p_offset;
|
||||
r->addr = (unsigned long long)elf64ph->p_vaddr;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("PPC64 ELF file, ph:\n");
|
||||
printf("p_type 0x%08x\n", elf64ph->p_type);
|
||||
printf("p_flags 0x%08x\n", elf64ph->p_flags);
|
||||
printf("p_offset 0x%016llx\n", elf64ph->p_offset);
|
||||
printf("p_vaddr 0x%016llx\n", elf64ph->p_vaddr);
|
||||
printf("p_paddr 0x%016llx\n", elf64ph->p_paddr);
|
||||
printf("p_filesz 0x%016llx\n", elf64ph->p_filesz);
|
||||
printf("p_memsz 0x%016llx\n", elf64ph->p_memsz);
|
||||
printf("p_align 0x%016llx\n", elf64ph->p_align);
|
||||
printf("... skipping 0x%08lx bytes of ELF header\n",
|
||||
(unsigned long)elf64ph->p_offset);
|
||||
#endif
|
||||
|
||||
return 64;
|
||||
}
|
||||
void get4k(FILE *file, char *buf )
|
||||
{
|
||||
unsigned j;
|
||||
unsigned num = fread(buf, 1, 4096, file);
|
||||
for ( j=num; j<4096; ++j )
|
||||
buf[j] = 0;
|
||||
}
|
||||
|
||||
void put4k(FILE *file, char *buf )
|
||||
{
|
||||
fwrite(buf, 1, 4096, file);
|
||||
}
|
||||
|
||||
void death(const char *msg, FILE *fdesc, const char *fname)
|
||||
{
|
||||
fprintf(stderr, msg);
|
||||
fclose(fdesc);
|
||||
unlink(fname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char inbuf[4096];
|
||||
struct addr_range vmlinux;
|
||||
FILE *ramDisk;
|
||||
FILE *inputVmlinux;
|
||||
FILE *outputVmlinux;
|
||||
|
||||
char *rd_name, *lx_name, *out_name;
|
||||
|
||||
size_t i;
|
||||
unsigned long ramFileLen;
|
||||
unsigned long ramLen;
|
||||
unsigned long roundR;
|
||||
unsigned long offset_end;
|
||||
|
||||
unsigned long kernelLen;
|
||||
unsigned long actualKernelLen;
|
||||
unsigned long round;
|
||||
unsigned long roundedKernelLen;
|
||||
unsigned long ramStartOffs;
|
||||
unsigned long ramPages;
|
||||
unsigned long roundedKernelPages;
|
||||
unsigned long hvReleaseData;
|
||||
u_int32_t eyeCatcher = 0xc8a5d9c4;
|
||||
unsigned long naca;
|
||||
unsigned long xRamDisk;
|
||||
unsigned long xRamDiskSize;
|
||||
long padPages;
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Name of RAM disk file missing.\n");
|
||||
exit(1);
|
||||
}
|
||||
rd_name = argv[1];
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Name of vmlinux file missing.\n");
|
||||
exit(1);
|
||||
}
|
||||
lx_name = argv[2];
|
||||
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "Name of vmlinux output file missing.\n");
|
||||
exit(1);
|
||||
}
|
||||
out_name = argv[3];
|
||||
|
||||
|
||||
ramDisk = fopen(rd_name, "r");
|
||||
if ( ! ramDisk ) {
|
||||
fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", rd_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
inputVmlinux = fopen(lx_name, "r");
|
||||
if ( ! inputVmlinux ) {
|
||||
fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", lx_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
outputVmlinux = fopen(out_name, "w+");
|
||||
if ( ! outputVmlinux ) {
|
||||
fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", out_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = fread(inbuf, 1, sizeof(inbuf), inputVmlinux);
|
||||
if (i != sizeof(inbuf)) {
|
||||
fprintf(stderr, "can not read vmlinux file %s: %u\n", lx_name, i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = check_elf64(inbuf, sizeof(inbuf), &vmlinux);
|
||||
if (i == 0) {
|
||||
fprintf(stderr, "You must have a linux kernel specified as argv[2]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Input Vmlinux file */
|
||||
fseek(inputVmlinux, 0, SEEK_END);
|
||||
kernelLen = ftell(inputVmlinux);
|
||||
fseek(inputVmlinux, 0, SEEK_SET);
|
||||
printf("kernel file size = %lu\n", kernelLen);
|
||||
|
||||
actualKernelLen = kernelLen - ElfHeaderSize;
|
||||
|
||||
printf("actual kernel length (minus ELF header) = %lu\n", actualKernelLen);
|
||||
|
||||
round = actualKernelLen % 4096;
|
||||
roundedKernelLen = actualKernelLen;
|
||||
if ( round )
|
||||
roundedKernelLen += (4096 - round);
|
||||
printf("Vmlinux length rounded up to a 4k multiple = %ld/0x%lx \n", roundedKernelLen, roundedKernelLen);
|
||||
roundedKernelPages = roundedKernelLen / 4096;
|
||||
printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages);
|
||||
|
||||
offset_end = _ALIGN_UP(vmlinux.memsize, 4096);
|
||||
/* calc how many pages we need to insert between the vmlinux and the start of the ram disk */
|
||||
padPages = offset_end/4096 - roundedKernelPages;
|
||||
|
||||
/* Check and see if the vmlinux is already larger than _end in System.map */
|
||||
if (padPages < 0) {
|
||||
/* vmlinux is larger than _end - adjust the offset to the start of the embedded ram disk */
|
||||
offset_end = roundedKernelLen;
|
||||
printf("vmlinux is larger than _end indicates it needs to be - offset_end = %lx \n", offset_end);
|
||||
padPages = 0;
|
||||
printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
|
||||
}
|
||||
else {
|
||||
/* _end is larger than vmlinux - use the offset to _end that we calculated from the system map */
|
||||
printf("vmlinux is smaller than _end indicates is needed - offset_end = %lx \n", offset_end);
|
||||
printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Input Ram Disk file */
|
||||
// Set the offset that the ram disk will be started at.
|
||||
ramStartOffs = offset_end; /* determined from the input vmlinux file and the system map */
|
||||
printf("Ram Disk will start at offset = 0x%lx \n", ramStartOffs);
|
||||
|
||||
fseek(ramDisk, 0, SEEK_END);
|
||||
ramFileLen = ftell(ramDisk);
|
||||
fseek(ramDisk, 0, SEEK_SET);
|
||||
printf("%s file size = %ld/0x%lx \n", rd_name, ramFileLen, ramFileLen);
|
||||
|
||||
ramLen = ramFileLen;
|
||||
|
||||
roundR = 4096 - (ramLen % 4096);
|
||||
if ( roundR ) {
|
||||
printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
|
||||
ramLen += roundR;
|
||||
}
|
||||
|
||||
printf("Rounded RAM disk size is %ld/0x%lx \n", ramLen, ramLen);
|
||||
ramPages = ramLen / 4096;
|
||||
printf("RAM disk pages to copy = %ld/0x%lx\n", ramPages, ramPages);
|
||||
|
||||
|
||||
|
||||
// Copy 64K ELF header
|
||||
for (i=0; i<(ElfPages); ++i) {
|
||||
get4k( inputVmlinux, inbuf );
|
||||
put4k( outputVmlinux, inbuf );
|
||||
}
|
||||
|
||||
/* Copy the vmlinux (as full pages). */
|
||||
fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
|
||||
for ( i=0; i<roundedKernelPages; ++i ) {
|
||||
get4k( inputVmlinux, inbuf );
|
||||
put4k( outputVmlinux, inbuf );
|
||||
}
|
||||
|
||||
/* Insert pad pages (if appropriate) that are needed between */
|
||||
/* | the end of the vmlinux and the ram disk. */
|
||||
for (i=0; i<padPages; ++i) {
|
||||
memset(inbuf, 0, 4096);
|
||||
put4k(outputVmlinux, inbuf);
|
||||
}
|
||||
|
||||
/* Copy the ram disk (as full pages). */
|
||||
for ( i=0; i<ramPages; ++i ) {
|
||||
get4k( ramDisk, inbuf );
|
||||
put4k( outputVmlinux, inbuf );
|
||||
}
|
||||
|
||||
/* Close the input files */
|
||||
fclose(ramDisk);
|
||||
fclose(inputVmlinux);
|
||||
/* And flush the written output file */
|
||||
fflush(outputVmlinux);
|
||||
|
||||
|
||||
|
||||
/* Fixup the new vmlinux to contain the ram disk starting offset (xRamDisk) and the ram disk size (xRamDiskSize) */
|
||||
/* fseek to the hvReleaseData pointer */
|
||||
fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
|
||||
if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
|
||||
death("Could not read hvReleaseData pointer\n", outputVmlinux, out_name);
|
||||
}
|
||||
hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
|
||||
printf("hvReleaseData is at %08lx\n", hvReleaseData);
|
||||
|
||||
/* fseek to the hvReleaseData */
|
||||
fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
|
||||
if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
|
||||
death("Could not read hvReleaseData\n", outputVmlinux, out_name);
|
||||
}
|
||||
/* Check hvReleaseData sanity */
|
||||
if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
|
||||
death("hvReleaseData is invalid\n", outputVmlinux, out_name);
|
||||
}
|
||||
/* Get the naca pointer */
|
||||
naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE;
|
||||
printf("Naca is at offset 0x%lx \n", naca);
|
||||
|
||||
/* fseek to the naca */
|
||||
fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
|
||||
if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
|
||||
death("Could not read naca\n", outputVmlinux, out_name);
|
||||
}
|
||||
xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
|
||||
xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
|
||||
/* Make sure a RAM disk isn't already present */
|
||||
if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
|
||||
death("RAM disk is already attached to this kernel\n", outputVmlinux, out_name);
|
||||
}
|
||||
/* Fill in the values */
|
||||
*((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
|
||||
*((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
|
||||
|
||||
/* Write out the new naca */
|
||||
fflush(outputVmlinux);
|
||||
fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
|
||||
if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
|
||||
death("Could not write naca\n", outputVmlinux, out_name);
|
||||
}
|
||||
printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08lx\n",
|
||||
ramPages, ramStartOffs);
|
||||
|
||||
/* Done */
|
||||
fclose(outputVmlinux);
|
||||
/* Set permission to executable */
|
||||
chmod(out_name, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
205
arch/powerpc/boot/addnote.c
一般檔案
205
arch/powerpc/boot/addnote.c
一般檔案
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Program to hack in a PT_NOTE program header entry in an ELF file.
|
||||
* This is needed for OF on RS/6000s to load an image correctly.
|
||||
* Note that OF needs a program header entry for the note, not an
|
||||
* ELF section.
|
||||
*
|
||||
* Copyright 2000 Paul Mackerras.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Usage: addnote zImage
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
/* CHRP note section */
|
||||
char arch[] = "PowerPC";
|
||||
|
||||
#define N_DESCR 6
|
||||
unsigned int descr[N_DESCR] = {
|
||||
0xffffffff, /* real-mode = true */
|
||||
0x00c00000, /* real-base, i.e. where we expect OF to be */
|
||||
0xffffffff, /* real-size */
|
||||
0xffffffff, /* virt-base */
|
||||
0xffffffff, /* virt-size */
|
||||
0x4000, /* load-base */
|
||||
};
|
||||
|
||||
/* RPA note section */
|
||||
char rpaname[] = "IBM,RPA-Client-Config";
|
||||
|
||||
/*
|
||||
* Note: setting ignore_my_client_config *should* mean that OF ignores
|
||||
* all the other fields, but there is a firmware bug which means that
|
||||
* it looks at the splpar field at least. So these values need to be
|
||||
* reasonable.
|
||||
*/
|
||||
#define N_RPA_DESCR 8
|
||||
unsigned int rpanote[N_RPA_DESCR] = {
|
||||
0, /* lparaffinity */
|
||||
64, /* min_rmo_size */
|
||||
0, /* min_rmo_percent */
|
||||
40, /* max_pft_size */
|
||||
1, /* splpar */
|
||||
-1, /* min_load */
|
||||
0, /* new_mem_def */
|
||||
1, /* ignore_my_client_config */
|
||||
};
|
||||
|
||||
#define ROUNDUP(len) (((len) + 3) & ~3)
|
||||
|
||||
unsigned char buf[512];
|
||||
|
||||
#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1]))
|
||||
#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2))
|
||||
|
||||
#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \
|
||||
buf[(off) + 1] = (v) & 0xff)
|
||||
#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \
|
||||
PUT_16BE((off) + 2, (v)))
|
||||
|
||||
/* Structure of an ELF file */
|
||||
#define E_IDENT 0 /* ELF header */
|
||||
#define E_PHOFF 28
|
||||
#define E_PHENTSIZE 42
|
||||
#define E_PHNUM 44
|
||||
#define E_HSIZE 52 /* size of ELF header */
|
||||
|
||||
#define EI_MAGIC 0 /* offsets in E_IDENT area */
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
|
||||
#define PH_TYPE 0 /* ELF program header */
|
||||
#define PH_OFFSET 4
|
||||
#define PH_FILESZ 16
|
||||
#define PH_HSIZE 32 /* size of program header */
|
||||
|
||||
#define PT_NOTE 4 /* Program header type = note */
|
||||
|
||||
#define ELFCLASS32 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
|
||||
|
||||
int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
int fd, n, i;
|
||||
int ph, ps, np;
|
||||
int nnote, nnote2, ns;
|
||||
|
||||
if (ac != 2) {
|
||||
fprintf(stderr, "Usage: %s elf-file\n", av[0]);
|
||||
exit(1);
|
||||
}
|
||||
fd = open(av[1], O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror(av[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
|
||||
nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
|
||||
|
||||
n = read(fd, buf, sizeof(buf));
|
||||
if (n < 0) {
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
|
||||
goto notelf;
|
||||
|
||||
if (buf[E_IDENT+EI_CLASS] != ELFCLASS32
|
||||
|| buf[E_IDENT+EI_DATA] != ELFDATA2MSB) {
|
||||
fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n",
|
||||
av[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ph = GET_32BE(E_PHOFF);
|
||||
ps = GET_16BE(E_PHENTSIZE);
|
||||
np = GET_16BE(E_PHNUM);
|
||||
if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
|
||||
goto notelf;
|
||||
if (ph + (np + 2) * ps + nnote + nnote2 > n)
|
||||
goto nospace;
|
||||
|
||||
for (i = 0; i < np; ++i) {
|
||||
if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
|
||||
fprintf(stderr, "%s already has a note entry\n",
|
||||
av[1]);
|
||||
exit(0);
|
||||
}
|
||||
ph += ps;
|
||||
}
|
||||
|
||||
/* XXX check that the area we want to use is all zeroes */
|
||||
for (i = 0; i < 2 * ps + nnote + nnote2; ++i)
|
||||
if (buf[ph + i] != 0)
|
||||
goto nospace;
|
||||
|
||||
/* fill in the program header entry */
|
||||
ns = ph + 2 * ps;
|
||||
PUT_32BE(ph + PH_TYPE, PT_NOTE);
|
||||
PUT_32BE(ph + PH_OFFSET, ns);
|
||||
PUT_32BE(ph + PH_FILESZ, nnote);
|
||||
|
||||
/* fill in the note area we point to */
|
||||
/* XXX we should probably make this a proper section */
|
||||
PUT_32BE(ns, strlen(arch) + 1);
|
||||
PUT_32BE(ns + 4, N_DESCR * 4);
|
||||
PUT_32BE(ns + 8, 0x1275);
|
||||
strcpy((char *) &buf[ns + 12], arch);
|
||||
ns += 12 + strlen(arch) + 1;
|
||||
for (i = 0; i < N_DESCR; ++i, ns += 4)
|
||||
PUT_32BE(ns, descr[i]);
|
||||
|
||||
/* fill in the second program header entry and the RPA note area */
|
||||
ph += ps;
|
||||
PUT_32BE(ph + PH_TYPE, PT_NOTE);
|
||||
PUT_32BE(ph + PH_OFFSET, ns);
|
||||
PUT_32BE(ph + PH_FILESZ, nnote2);
|
||||
|
||||
/* fill in the note area we point to */
|
||||
PUT_32BE(ns, strlen(rpaname) + 1);
|
||||
PUT_32BE(ns + 4, sizeof(rpanote));
|
||||
PUT_32BE(ns + 8, 0x12759999);
|
||||
strcpy((char *) &buf[ns + 12], rpaname);
|
||||
ns += 12 + ROUNDUP(strlen(rpaname) + 1);
|
||||
for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
|
||||
PUT_32BE(ns, rpanote[i]);
|
||||
|
||||
/* Update the number of program headers */
|
||||
PUT_16BE(E_PHNUM, np + 2);
|
||||
|
||||
/* write back */
|
||||
lseek(fd, (long) 0, SEEK_SET);
|
||||
i = write(fd, buf, n);
|
||||
if (i < 0) {
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
if (i < n) {
|
||||
fprintf(stderr, "%s: write truncated\n", av[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
||||
notelf:
|
||||
fprintf(stderr, "%s does not appear to be an ELF file\n", av[1]);
|
||||
exit(1);
|
||||
|
||||
nospace:
|
||||
fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
|
||||
av[1]);
|
||||
exit(1);
|
||||
}
|
59
arch/powerpc/boot/crt0.S
一般檔案
59
arch/powerpc/boot/crt0.S
一般檔案
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) Paul Mackerras 1997.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* NOTE: this code runs in 32 bit mode and is packaged as ELF32.
|
||||
*/
|
||||
|
||||
#include "ppc_asm.h"
|
||||
|
||||
.text
|
||||
.globl _zimage_start
|
||||
_zimage_start:
|
||||
bl reloc_offset
|
||||
|
||||
reloc_offset:
|
||||
mflr r0
|
||||
lis r9,reloc_offset@ha
|
||||
addi r9,r9,reloc_offset@l
|
||||
subf. r0,r9,r0
|
||||
beq clear_caches
|
||||
|
||||
reloc_got2:
|
||||
lis r9,__got2_start@ha
|
||||
addi r9,r9,__got2_start@l
|
||||
lis r8,__got2_end@ha
|
||||
addi r8,r8,__got2_end@l
|
||||
subf. r8,r9,r8
|
||||
beq clear_caches
|
||||
srwi. r8,r8,2
|
||||
mtctr r8
|
||||
add r9,r0,r9
|
||||
reloc_got2_loop:
|
||||
lwz r8,0(r9)
|
||||
add r8,r8,r0
|
||||
stw r8,0(r9)
|
||||
addi r9,r9,4
|
||||
bdnz reloc_got2_loop
|
||||
|
||||
clear_caches:
|
||||
lis r9,_start@h
|
||||
add r9,r0,r9
|
||||
lis r8,_etext@ha
|
||||
addi r8,r8,_etext@l
|
||||
add r8,r0,r8
|
||||
1: dcbf r0,r9
|
||||
icbi r0,r9
|
||||
addi r9,r9,0x20
|
||||
cmplwi 0,r9,8
|
||||
blt 1b
|
||||
sync
|
||||
isync
|
||||
|
||||
mr r6,r1
|
||||
b start
|
||||
|
58
arch/powerpc/boot/div64.S
一般檔案
58
arch/powerpc/boot/div64.S
一般檔案
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Divide a 64-bit unsigned number by a 32-bit unsigned number.
|
||||
* This routine assumes that the top 32 bits of the dividend are
|
||||
* non-zero to start with.
|
||||
* On entry, r3 points to the dividend, which get overwritten with
|
||||
* the 64-bit quotient, and r4 contains the divisor.
|
||||
* On exit, r3 contains the remainder.
|
||||
*
|
||||
* Copyright (C) 2002 Paul Mackerras, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "ppc_asm.h"
|
||||
|
||||
.globl __div64_32
|
||||
__div64_32:
|
||||
lwz r5,0(r3) # get the dividend into r5/r6
|
||||
lwz r6,4(r3)
|
||||
cmplw r5,r4
|
||||
li r7,0
|
||||
li r8,0
|
||||
blt 1f
|
||||
divwu r7,r5,r4 # if dividend.hi >= divisor,
|
||||
mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor
|
||||
subf. r5,r0,r5 # dividend.hi %= divisor
|
||||
beq 3f
|
||||
1: mr r11,r5 # here dividend.hi != 0
|
||||
andis. r0,r5,0xc000
|
||||
bne 2f
|
||||
cntlzw r0,r5 # we are shifting the dividend right
|
||||
li r10,-1 # to make it < 2^32, and shifting
|
||||
srw r10,r10,r0 # the divisor right the same amount,
|
||||
add r9,r4,r10 # rounding up (so the estimate cannot
|
||||
andc r11,r6,r10 # ever be too large, only too small)
|
||||
andc r9,r9,r10
|
||||
or r11,r5,r11
|
||||
rotlw r9,r9,r0
|
||||
rotlw r11,r11,r0
|
||||
divwu r11,r11,r9 # then we divide the shifted quantities
|
||||
2: mullw r10,r11,r4 # to get an estimate of the quotient,
|
||||
mulhwu r9,r11,r4 # multiply the estimate by the divisor,
|
||||
subfc r6,r10,r6 # take the product from the divisor,
|
||||
add r8,r8,r11 # and add the estimate to the accumulated
|
||||
subfe. r5,r9,r5 # quotient
|
||||
bne 1b
|
||||
3: cmplw r6,r4
|
||||
blt 4f
|
||||
divwu r0,r6,r4 # perform the remaining 32-bit division
|
||||
mullw r10,r0,r4 # and get the remainder
|
||||
add r8,r8,r0
|
||||
subf r6,r10,r6
|
||||
4: stw r7,0(r3) # return the quotient in *r3
|
||||
stw r8,4(r3)
|
||||
mr r3,r6 # return the remainder in r3
|
||||
blr
|
149
arch/powerpc/boot/elf.h
一般檔案
149
arch/powerpc/boot/elf.h
一般檔案
@@ -0,0 +1,149 @@
|
||||
#ifndef _PPC_BOOT_ELF_H_
|
||||
#define _PPC_BOOT_ELF_H_
|
||||
|
||||
/* 32-bit ELF base types. */
|
||||
typedef unsigned int Elf32_Addr;
|
||||
typedef unsigned short Elf32_Half;
|
||||
typedef unsigned int Elf32_Off;
|
||||
typedef signed int Elf32_Sword;
|
||||
typedef unsigned int Elf32_Word;
|
||||
|
||||
/* 64-bit ELF base types. */
|
||||
typedef unsigned long long Elf64_Addr;
|
||||
typedef unsigned short Elf64_Half;
|
||||
typedef signed short Elf64_SHalf;
|
||||
typedef unsigned long long Elf64_Off;
|
||||
typedef signed int Elf64_Sword;
|
||||
typedef unsigned int Elf64_Word;
|
||||
typedef unsigned long long Elf64_Xword;
|
||||
typedef signed long long Elf64_Sxword;
|
||||
|
||||
/* These constants are for the segment types stored in the image headers */
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define PT_NOTE 4
|
||||
#define PT_SHLIB 5
|
||||
#define PT_PHDR 6
|
||||
#define PT_TLS 7 /* Thread local storage segment */
|
||||
#define PT_LOOS 0x60000000 /* OS-specific */
|
||||
#define PT_HIOS 0x6fffffff /* OS-specific */
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7fffffff
|
||||
#define PT_GNU_EH_FRAME 0x6474e550
|
||||
|
||||
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
|
||||
|
||||
/* These constants define the different elf file types */
|
||||
#define ET_NONE 0
|
||||
#define ET_REL 1
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define ET_CORE 4
|
||||
#define ET_LOPROC 0xff00
|
||||
#define ET_HIPROC 0xffff
|
||||
|
||||
/* These constants define the various ELF target machines */
|
||||
#define EM_NONE 0
|
||||
#define EM_PPC 20 /* PowerPC */
|
||||
#define EM_PPC64 21 /* PowerPC64 */
|
||||
|
||||
#define EI_NIDENT 16
|
||||
|
||||
typedef struct elf32_hdr {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry; /* Entry point */
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct elf64_hdr {
|
||||
unsigned char e_ident[16]; /* ELF "magic number" */
|
||||
Elf64_Half e_type;
|
||||
Elf64_Half e_machine;
|
||||
Elf64_Word e_version;
|
||||
Elf64_Addr e_entry; /* Entry point virtual address */
|
||||
Elf64_Off e_phoff; /* Program header table file offset */
|
||||
Elf64_Off e_shoff; /* Section header table file offset */
|
||||
Elf64_Word e_flags;
|
||||
Elf64_Half e_ehsize;
|
||||
Elf64_Half e_phentsize;
|
||||
Elf64_Half e_phnum;
|
||||
Elf64_Half e_shentsize;
|
||||
Elf64_Half e_shnum;
|
||||
Elf64_Half e_shstrndx;
|
||||
} Elf64_Ehdr;
|
||||
|
||||
/* These constants define the permissions on sections in the program
|
||||
header, p_flags. */
|
||||
#define PF_R 0x4
|
||||
#define PF_W 0x2
|
||||
#define PF_X 0x1
|
||||
|
||||
typedef struct elf32_phdr {
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
} Elf32_Phdr;
|
||||
|
||||
typedef struct elf64_phdr {
|
||||
Elf64_Word p_type;
|
||||
Elf64_Word p_flags;
|
||||
Elf64_Off p_offset; /* Segment file offset */
|
||||
Elf64_Addr p_vaddr; /* Segment virtual address */
|
||||
Elf64_Addr p_paddr; /* Segment physical address */
|
||||
Elf64_Xword p_filesz; /* Segment size in file */
|
||||
Elf64_Xword p_memsz; /* Segment size in memory */
|
||||
Elf64_Xword p_align; /* Segment alignment, file & memory */
|
||||
} Elf64_Phdr;
|
||||
|
||||
#define EI_MAG0 0 /* e_ident[] indexes */
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
#define EI_OSABI 7
|
||||
#define EI_PAD 8
|
||||
|
||||
#define ELFMAG0 0x7f /* EI_MAG */
|
||||
#define ELFMAG1 'E'
|
||||
#define ELFMAG2 'L'
|
||||
#define ELFMAG3 'F'
|
||||
#define ELFMAG "\177ELF"
|
||||
#define SELFMAG 4
|
||||
|
||||
#define ELFCLASSNONE 0 /* EI_CLASS */
|
||||
#define ELFCLASS32 1
|
||||
#define ELFCLASS64 2
|
||||
#define ELFCLASSNUM 3
|
||||
|
||||
#define ELFDATANONE 0 /* e_ident[EI_DATA] */
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
#define EV_NONE 0 /* e_version, EI_VERSION */
|
||||
#define EV_CURRENT 1
|
||||
#define EV_NUM 2
|
||||
|
||||
#define ELFOSABI_NONE 0
|
||||
#define ELFOSABI_LINUX 3
|
||||
|
||||
#endif /* _PPC_BOOT_ELF_H_ */
|
42
arch/powerpc/boot/install.sh
一般檔案
42
arch/powerpc/boot/install.sh
一般檔案
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# arch/ppc64/boot/install.sh
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU General Public
|
||||
# License. See the file "COPYING" in the main directory of this archive
|
||||
# for more details.
|
||||
#
|
||||
# Copyright (C) 1995 by Linus Torvalds
|
||||
#
|
||||
# Blatantly stolen from in arch/i386/boot/install.sh by Dave Hansen
|
||||
#
|
||||
# "make install" script for ppc64 architecture
|
||||
#
|
||||
# Arguments:
|
||||
# $1 - kernel version
|
||||
# $2 - kernel image file
|
||||
# $3 - kernel map file
|
||||
# $4 - default install path (blank if root directory)
|
||||
# $5 - kernel boot file, the zImage
|
||||
#
|
||||
|
||||
# User may have a custom install script
|
||||
|
||||
if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
|
||||
if [ -x /sbin/${CROSS_COMPILE}installkernel ]; then exec /sbin/${CROSS_COMPILE}installkernel "$@"; fi
|
||||
|
||||
# Default install
|
||||
|
||||
# this should work for both the pSeries zImage and the iSeries vmlinux.sm
|
||||
image_name=`basename $2`
|
||||
|
||||
if [ -f $4/$image_name ]; then
|
||||
mv $4/$image_name $4/$image_name.old
|
||||
fi
|
||||
|
||||
if [ -f $4/System.map ]; then
|
||||
mv $4/System.map $4/System.old
|
||||
fi
|
||||
|
||||
cat $2 > $4/$image_name
|
||||
cp $3 $4/System.map
|
321
arch/powerpc/boot/main.c
一般檔案
321
arch/powerpc/boot/main.c
一般檔案
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright (C) Paul Mackerras 1997.
|
||||
*
|
||||
* Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include "elf.h"
|
||||
#include "page.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "prom.h"
|
||||
#include "zlib.h"
|
||||
|
||||
extern void flush_cache(void *, unsigned long);
|
||||
|
||||
|
||||
/* Value picked to match that used by yaboot */
|
||||
#define PROG_START 0x01400000
|
||||
#define RAM_END (512<<20) // Fixme: use OF */
|
||||
#define ONE_MB 0x100000
|
||||
|
||||
extern char _start[];
|
||||
extern char __bss_start[];
|
||||
extern char _end[];
|
||||
extern char _vmlinux_start[];
|
||||
extern char _vmlinux_end[];
|
||||
extern char _initrd_start[];
|
||||
extern char _initrd_end[];
|
||||
|
||||
struct addr_range {
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
unsigned long memsize;
|
||||
};
|
||||
static struct addr_range vmlinux;
|
||||
static struct addr_range vmlinuz;
|
||||
static struct addr_range initrd;
|
||||
|
||||
static unsigned long elfoffset;
|
||||
|
||||
static char scratch[46912]; /* scratch space for gunzip, from zlib_inflate_workspacesize() */
|
||||
static char elfheader[256];
|
||||
|
||||
|
||||
typedef void (*kernel_entry_t)( unsigned long,
|
||||
unsigned long,
|
||||
void *,
|
||||
void *);
|
||||
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
static unsigned long claim_base;
|
||||
|
||||
#define HEAD_CRC 2
|
||||
#define EXTRA_FIELD 4
|
||||
#define ORIG_NAME 8
|
||||
#define COMMENT 0x10
|
||||
#define RESERVED 0xe0
|
||||
|
||||
static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
|
||||
{
|
||||
z_stream s;
|
||||
int r, i, flags;
|
||||
|
||||
/* skip header */
|
||||
i = 10;
|
||||
flags = src[3];
|
||||
if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
|
||||
printf("bad gzipped data\n\r");
|
||||
exit();
|
||||
}
|
||||
if ((flags & EXTRA_FIELD) != 0)
|
||||
i = 12 + src[10] + (src[11] << 8);
|
||||
if ((flags & ORIG_NAME) != 0)
|
||||
while (src[i++] != 0)
|
||||
;
|
||||
if ((flags & COMMENT) != 0)
|
||||
while (src[i++] != 0)
|
||||
;
|
||||
if ((flags & HEAD_CRC) != 0)
|
||||
i += 2;
|
||||
if (i >= *lenp) {
|
||||
printf("gunzip: ran out of data in header\n\r");
|
||||
exit();
|
||||
}
|
||||
|
||||
if (zlib_inflate_workspacesize() > sizeof(scratch)) {
|
||||
printf("gunzip needs more mem\n");
|
||||
exit();
|
||||
}
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.workspace = scratch;
|
||||
r = zlib_inflateInit2(&s, -MAX_WBITS);
|
||||
if (r != Z_OK) {
|
||||
printf("inflateInit2 returned %d\n\r", r);
|
||||
exit();
|
||||
}
|
||||
s.next_in = src + i;
|
||||
s.avail_in = *lenp - i;
|
||||
s.next_out = dst;
|
||||
s.avail_out = dstlen;
|
||||
r = zlib_inflate(&s, Z_FULL_FLUSH);
|
||||
if (r != Z_OK && r != Z_STREAM_END) {
|
||||
printf("inflate returned %d msg: %s\n\r", r, s.msg);
|
||||
exit();
|
||||
}
|
||||
*lenp = s.next_out - (unsigned char *) dst;
|
||||
zlib_inflateEnd(&s);
|
||||
}
|
||||
|
||||
static unsigned long try_claim(unsigned long size)
|
||||
{
|
||||
unsigned long addr = 0;
|
||||
|
||||
for(; claim_base < RAM_END; claim_base += ONE_MB) {
|
||||
#ifdef DEBUG
|
||||
printf(" trying: 0x%08lx\n\r", claim_base);
|
||||
#endif
|
||||
addr = (unsigned long)claim(claim_base, size, 0);
|
||||
if ((void *)addr != (void *)-1)
|
||||
break;
|
||||
}
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
claim_base = PAGE_ALIGN(claim_base + size);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int is_elf64(void *hdr)
|
||||
{
|
||||
Elf64_Ehdr *elf64 = hdr;
|
||||
Elf64_Phdr *elf64ph;
|
||||
unsigned int i;
|
||||
|
||||
if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 &&
|
||||
elf64->e_ident[EI_MAG1] == ELFMAG1 &&
|
||||
elf64->e_ident[EI_MAG2] == ELFMAG2 &&
|
||||
elf64->e_ident[EI_MAG3] == ELFMAG3 &&
|
||||
elf64->e_ident[EI_CLASS] == ELFCLASS64 &&
|
||||
elf64->e_ident[EI_DATA] == ELFDATA2MSB &&
|
||||
elf64->e_type == ET_EXEC &&
|
||||
elf64->e_machine == EM_PPC64))
|
||||
return 0;
|
||||
|
||||
elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
|
||||
(unsigned long)elf64->e_phoff);
|
||||
for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
|
||||
if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0)
|
||||
break;
|
||||
if (i >= (unsigned int)elf64->e_phnum)
|
||||
return 0;
|
||||
|
||||
elfoffset = (unsigned long)elf64ph->p_offset;
|
||||
vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
|
||||
vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_elf32(void *hdr)
|
||||
{
|
||||
Elf32_Ehdr *elf32 = hdr;
|
||||
Elf32_Phdr *elf32ph;
|
||||
unsigned int i;
|
||||
|
||||
if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 &&
|
||||
elf32->e_ident[EI_MAG1] == ELFMAG1 &&
|
||||
elf32->e_ident[EI_MAG2] == ELFMAG2 &&
|
||||
elf32->e_ident[EI_MAG3] == ELFMAG3 &&
|
||||
elf32->e_ident[EI_CLASS] == ELFCLASS32 &&
|
||||
elf32->e_ident[EI_DATA] == ELFDATA2MSB &&
|
||||
elf32->e_type == ET_EXEC &&
|
||||
elf32->e_machine == EM_PPC))
|
||||
return 0;
|
||||
|
||||
elf32 = (Elf32_Ehdr *)elfheader;
|
||||
elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
|
||||
for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
|
||||
if (elf32ph->p_type == PT_LOAD && elf32ph->p_offset != 0)
|
||||
break;
|
||||
if (i >= elf32->e_phnum)
|
||||
return 0;
|
||||
|
||||
elfoffset = elf32ph->p_offset;
|
||||
vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
|
||||
vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
|
||||
{
|
||||
int len;
|
||||
kernel_entry_t kernel_entry;
|
||||
|
||||
memset(__bss_start, 0, _end - __bss_start);
|
||||
|
||||
prom = (int (*)(void *)) promptr;
|
||||
chosen_handle = finddevice("/chosen");
|
||||
if (chosen_handle == (void *) -1)
|
||||
exit();
|
||||
if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
|
||||
exit();
|
||||
stderr = stdout;
|
||||
if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
|
||||
exit();
|
||||
|
||||
printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
|
||||
|
||||
vmlinuz.addr = (unsigned long)_vmlinux_start;
|
||||
vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
|
||||
|
||||
/* gunzip the ELF header of the kernel */
|
||||
if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
|
||||
len = vmlinuz.size;
|
||||
gunzip(elfheader, sizeof(elfheader),
|
||||
(unsigned char *)vmlinuz.addr, &len);
|
||||
} else
|
||||
memcpy(elfheader, (const void *)vmlinuz.addr, sizeof(elfheader));
|
||||
|
||||
if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
|
||||
printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
|
||||
exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* The first available claim_base must be above the end of the
|
||||
* the loaded kernel wrapper file (_start to _end includes the
|
||||
* initrd image if it is present) and rounded up to a nice
|
||||
* 1 MB boundary for good measure.
|
||||
*/
|
||||
|
||||
claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
|
||||
|
||||
#if defined(PROG_START)
|
||||
/*
|
||||
* Maintain a "magic" minimum address. This keeps some older
|
||||
* firmware platforms running.
|
||||
*/
|
||||
|
||||
if (claim_base < PROG_START)
|
||||
claim_base = PROG_START;
|
||||
#endif
|
||||
|
||||
/* We need to claim the memsize plus the file offset since gzip
|
||||
* will expand the header (file offset), then the kernel, then
|
||||
* possible rubbish we don't care about. But the kernel bss must
|
||||
* be claimed (it will be zero'd by the kernel itself)
|
||||
*/
|
||||
printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
|
||||
vmlinux.addr = try_claim(vmlinux.memsize);
|
||||
if (vmlinux.addr == 0) {
|
||||
printf("Can't allocate memory for kernel image !\n\r");
|
||||
exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we try to claim memory for the initrd (and copy it there)
|
||||
*/
|
||||
initrd.size = (unsigned long)(_initrd_end - _initrd_start);
|
||||
initrd.memsize = initrd.size;
|
||||
if ( initrd.size > 0 ) {
|
||||
printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size);
|
||||
initrd.addr = try_claim(initrd.size);
|
||||
if (initrd.addr == 0) {
|
||||
printf("Can't allocate memory for initial ramdisk !\n\r");
|
||||
exit();
|
||||
}
|
||||
a1 = initrd.addr;
|
||||
a2 = initrd.size;
|
||||
printf("initial ramdisk moving 0x%lx <- 0x%lx (0x%lx bytes)\n\r",
|
||||
initrd.addr, (unsigned long)_initrd_start, initrd.size);
|
||||
memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size);
|
||||
printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd.addr));
|
||||
}
|
||||
|
||||
/* Eventually gunzip the kernel */
|
||||
if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
|
||||
printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
|
||||
vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
|
||||
len = vmlinuz.size;
|
||||
gunzip((void *)vmlinux.addr, vmlinux.memsize,
|
||||
(unsigned char *)vmlinuz.addr, &len);
|
||||
printf("done 0x%lx bytes\n\r", len);
|
||||
} else {
|
||||
memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size);
|
||||
}
|
||||
|
||||
/* Skip over the ELF header */
|
||||
#ifdef DEBUG
|
||||
printf("... skipping 0x%lx bytes of ELF header\n\r",
|
||||
elfoffset);
|
||||
#endif
|
||||
vmlinux.addr += elfoffset;
|
||||
|
||||
flush_cache((void *)vmlinux.addr, vmlinux.size);
|
||||
|
||||
kernel_entry = (kernel_entry_t)vmlinux.addr;
|
||||
#ifdef DEBUG
|
||||
printf( "kernel:\n\r"
|
||||
" entry addr = 0x%lx\n\r"
|
||||
" a1 = 0x%lx,\n\r"
|
||||
" a2 = 0x%lx,\n\r"
|
||||
" prom = 0x%lx,\n\r"
|
||||
" bi_recs = 0x%lx,\n\r",
|
||||
(unsigned long)kernel_entry, a1, a2,
|
||||
(unsigned long)prom, NULL);
|
||||
#endif
|
||||
|
||||
kernel_entry(a1, a2, prom, NULL);
|
||||
|
||||
printf("Error: Linux kernel returned to zImage bootloader!\n\r");
|
||||
|
||||
exit();
|
||||
}
|
||||
|
34
arch/powerpc/boot/page.h
一般檔案
34
arch/powerpc/boot/page.h
一般檔案
@@ -0,0 +1,34 @@
|
||||
#ifndef _PPC_BOOT_PAGE_H
|
||||
#define _PPC_BOOT_PAGE_H
|
||||
/*
|
||||
* Copyright (C) 2001 PPC64 Team, IBM Corp
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#define ASM_CONST(x) x
|
||||
#else
|
||||
#define __ASM_CONST(x) x##UL
|
||||
#define ASM_CONST(x) __ASM_CONST(x)
|
||||
#endif
|
||||
|
||||
/* PAGE_SHIFT determines the page size */
|
||||
#define PAGE_SHIFT 12
|
||||
#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)
|
||||
#define PAGE_MASK (~(PAGE_SIZE-1))
|
||||
|
||||
/* align addr on a size boundary - adjust address up/down if needed */
|
||||
#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
|
||||
#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))
|
||||
|
||||
/* align addr on a size boundary - adjust address up if needed */
|
||||
#define _ALIGN(addr,size) _ALIGN_UP(addr,size)
|
||||
|
||||
/* to align the pointer to the (next) page boundary */
|
||||
#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
|
||||
|
||||
#endif /* _PPC_BOOT_PAGE_H */
|
62
arch/powerpc/boot/ppc_asm.h
一般檔案
62
arch/powerpc/boot/ppc_asm.h
一般檔案
@@ -0,0 +1,62 @@
|
||||
#ifndef _PPC64_PPC_ASM_H
|
||||
#define _PPC64_PPC_ASM_H
|
||||
/*
|
||||
*
|
||||
* Definitions used by various bits of low-level assembly code on PowerPC.
|
||||
*
|
||||
* Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Condition Register Bit Fields */
|
||||
|
||||
#define cr0 0
|
||||
#define cr1 1
|
||||
#define cr2 2
|
||||
#define cr3 3
|
||||
#define cr4 4
|
||||
#define cr5 5
|
||||
#define cr6 6
|
||||
#define cr7 7
|
||||
|
||||
|
||||
/* General Purpose Registers (GPRs) */
|
||||
|
||||
#define r0 0
|
||||
#define r1 1
|
||||
#define r2 2
|
||||
#define r3 3
|
||||
#define r4 4
|
||||
#define r5 5
|
||||
#define r6 6
|
||||
#define r7 7
|
||||
#define r8 8
|
||||
#define r9 9
|
||||
#define r10 10
|
||||
#define r11 11
|
||||
#define r12 12
|
||||
#define r13 13
|
||||
#define r14 14
|
||||
#define r15 15
|
||||
#define r16 16
|
||||
#define r17 17
|
||||
#define r18 18
|
||||
#define r19 19
|
||||
#define r20 20
|
||||
#define r21 21
|
||||
#define r22 22
|
||||
#define r23 23
|
||||
#define r24 24
|
||||
#define r25 25
|
||||
#define r26 26
|
||||
#define r27 27
|
||||
#define r28 28
|
||||
#define r29 29
|
||||
#define r30 30
|
||||
#define r31 31
|
||||
|
||||
#endif /* _PPC64_PPC_ASM_H */
|
499
arch/powerpc/boot/prom.c
一般檔案
499
arch/powerpc/boot/prom.c
一般檔案
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Copyright (C) Paul Mackerras 1997.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "prom.h"
|
||||
|
||||
int (*prom)(void *);
|
||||
|
||||
void *chosen_handle;
|
||||
|
||||
void *stdin;
|
||||
void *stdout;
|
||||
void *stderr;
|
||||
|
||||
|
||||
int
|
||||
write(void *handle, void *ptr, int nb)
|
||||
{
|
||||
struct prom_args {
|
||||
char *service;
|
||||
int nargs;
|
||||
int nret;
|
||||
void *ihandle;
|
||||
void *addr;
|
||||
int len;
|
||||
int actual;
|
||||
} args;
|
||||
|
||||
args.service = "write";
|
||||
args.nargs = 3;
|
||||
args.nret = 1;
|
||||
args.ihandle = handle;
|
||||
args.addr = ptr;
|
||||
args.len = nb;
|
||||
args.actual = -1;
|
||||
(*prom)(&args);
|
||||
return args.actual;
|
||||
}
|
||||
|
||||
int
|
||||
read(void *handle, void *ptr, int nb)
|
||||
{
|
||||
struct prom_args {
|
||||
char *service;
|
||||
int nargs;
|
||||
int nret;
|
||||
void *ihandle;
|
||||
void *addr;
|
||||
int len;
|
||||
int actual;
|
||||
} args;
|
||||
|
||||
args.service = "read";
|
||||
args.nargs = 3;
|
||||
args.nret = 1;
|
||||
args.ihandle = handle;
|
||||
args.addr = ptr;
|
||||
args.len = nb;
|
||||
args.actual = -1;
|
||||
(*prom)(&args);
|
||||
return args.actual;
|
||||
}
|
||||
|
||||
void
|
||||
exit()
|
||||
{
|
||||
struct prom_args {
|
||||
char *service;
|
||||
} args;
|
||||
|
||||
for (;;) {
|
||||
args.service = "exit";
|
||||
(*prom)(&args);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pause(void)
|
||||
{
|
||||
struct prom_args {
|
||||
char *service;
|
||||
} args;
|
||||
|
||||
args.service = "enter";
|
||||
(*prom)(&args);
|
||||
}
|
||||
|
||||
void *
|
||||
finddevice(const char *name)
|
||||
{
|
||||
struct prom_args {
|
||||
char *service;
|
||||
int nargs;
|
||||
int nret;
|
||||
const char *devspec;
|
||||
void *phandle;
|
||||
} args;
|
||||
|
||||
args.service = "finddevice";
|
||||
args.nargs = 1;
|
||||
args.nret = 1;
|
||||
args.devspec = name;
|
||||
args.phandle = (void *) -1;
|
||||
(*prom)(&args);
|
||||
return args.phandle;
|
||||
}
|
||||
|
||||
void *
|
||||
claim(unsigned long virt, unsigned long size, unsigned long align)
|
||||
{
|
||||
struct prom_args {
|
||||
char *service;
|
||||
int nargs;
|
||||
int nret;
|
||||
unsigned int virt;
|
||||
unsigned int size;
|
||||
unsigned int align;
|
||||
void *ret;
|
||||
} args;
|
||||
|
||||
args.service = "claim";
|
||||
args.nargs = 3;
|
||||
args.nret = 1;
|
||||
args.virt = virt;
|
||||
args.size = size;
|
||||
args.align = align;
|
||||
(*prom)(&args);
|
||||
return args.ret;
|
||||
}
|
||||
|
||||
int
|
||||
getprop(void *phandle, const char *name, void *buf, int buflen)
|
||||
{
|
||||
struct prom_args {
|
||||
char *service;
|
||||
int nargs;
|
||||
int nret;
|
||||
void *phandle;
|
||||
const char *name;
|
||||
void *buf;
|
||||
int buflen;
|
||||
int size;
|
||||
} args;
|
||||
|
||||
args.service = "getprop";
|
||||
args.nargs = 4;
|
||||
args.nret = 1;
|
||||
args.phandle = phandle;
|
||||
args.name = name;
|
||||
args.buf = buf;
|
||||
args.buflen = buflen;
|
||||
args.size = -1;
|
||||
(*prom)(&args);
|
||||
return args.size;
|
||||
}
|
||||
|
||||
int
|
||||
putc(int c, void *f)
|
||||
{
|
||||
char ch = c;
|
||||
|
||||
if (c == '\n')
|
||||
putc('\r', f);
|
||||
return write(f, &ch, 1) == 1? c: -1;
|
||||
}
|
||||
|
||||
int
|
||||
putchar(int c)
|
||||
{
|
||||
return putc(c, stdout);
|
||||
}
|
||||
|
||||
int
|
||||
fputs(char *str, void *f)
|
||||
{
|
||||
int n = strlen(str);
|
||||
|
||||
return write(f, str, n) == n? 0: -1;
|
||||
}
|
||||
|
||||
size_t strnlen(const char * s, size_t count)
|
||||
{
|
||||
const char *sc;
|
||||
|
||||
for (sc = s; count-- && *sc != '\0'; ++sc)
|
||||
/* nothing */;
|
||||
return sc - s;
|
||||
}
|
||||
|
||||
extern unsigned int __div64_32(unsigned long long *dividend,
|
||||
unsigned int divisor);
|
||||
|
||||
/* The unnecessary pointer compare is there
|
||||
* to check for type safety (n must be 64bit)
|
||||
*/
|
||||
# define do_div(n,base) ({ \
|
||||
unsigned int __base = (base); \
|
||||
unsigned int __rem; \
|
||||
(void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \
|
||||
if (((n) >> 32) == 0) { \
|
||||
__rem = (unsigned int)(n) % __base; \
|
||||
(n) = (unsigned int)(n) / __base; \
|
||||
} else \
|
||||
__rem = __div64_32(&(n), __base); \
|
||||
__rem; \
|
||||
})
|
||||
|
||||
static int skip_atoi(const char **s)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
|
||||
i = i*10 + c - '0';
|
||||
return i;
|
||||
}
|
||||
|
||||
#define ZEROPAD 1 /* pad with zero */
|
||||
#define SIGN 2 /* unsigned/signed long */
|
||||
#define PLUS 4 /* show plus */
|
||||
#define SPACE 8 /* space if plus */
|
||||
#define LEFT 16 /* left justified */
|
||||
#define SPECIAL 32 /* 0x */
|
||||
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
||||
|
||||
static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
|
||||
{
|
||||
char c,sign,tmp[66];
|
||||
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
int i;
|
||||
|
||||
if (type & LARGE)
|
||||
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
if (type & LEFT)
|
||||
type &= ~ZEROPAD;
|
||||
if (base < 2 || base > 36)
|
||||
return 0;
|
||||
c = (type & ZEROPAD) ? '0' : ' ';
|
||||
sign = 0;
|
||||
if (type & SIGN) {
|
||||
if ((signed long long)num < 0) {
|
||||
sign = '-';
|
||||
num = - (signed long long)num;
|
||||
size--;
|
||||
} else if (type & PLUS) {
|
||||
sign = '+';
|
||||
size--;
|
||||
} else if (type & SPACE) {
|
||||
sign = ' ';
|
||||
size--;
|
||||
}
|
||||
}
|
||||
if (type & SPECIAL) {
|
||||
if (base == 16)
|
||||
size -= 2;
|
||||
else if (base == 8)
|
||||
size--;
|
||||
}
|
||||
i = 0;
|
||||
if (num == 0)
|
||||
tmp[i++]='0';
|
||||
else while (num != 0) {
|
||||
tmp[i++] = digits[do_div(num, base)];
|
||||
}
|
||||
if (i > precision)
|
||||
precision = i;
|
||||
size -= precision;
|
||||
if (!(type&(ZEROPAD+LEFT)))
|
||||
while(size-->0)
|
||||
*str++ = ' ';
|
||||
if (sign)
|
||||
*str++ = sign;
|
||||
if (type & SPECIAL) {
|
||||
if (base==8)
|
||||
*str++ = '0';
|
||||
else if (base==16) {
|
||||
*str++ = '0';
|
||||
*str++ = digits[33];
|
||||
}
|
||||
}
|
||||
if (!(type & LEFT))
|
||||
while (size-- > 0)
|
||||
*str++ = c;
|
||||
while (i < precision--)
|
||||
*str++ = '0';
|
||||
while (i-- > 0)
|
||||
*str++ = tmp[i];
|
||||
while (size-- > 0)
|
||||
*str++ = ' ';
|
||||
return str;
|
||||
}
|
||||
|
||||
int vsprintf(char *buf, const char *fmt, va_list args)
|
||||
{
|
||||
int len;
|
||||
unsigned long long num;
|
||||
int i, base;
|
||||
char * str;
|
||||
const char *s;
|
||||
|
||||
int flags; /* flags to number() */
|
||||
|
||||
int field_width; /* width of output field */
|
||||
int precision; /* min. # of digits for integers; max
|
||||
number of chars for from string */
|
||||
int qualifier; /* 'h', 'l', or 'L' for integer fields */
|
||||
/* 'z' support added 23/7/1999 S.H. */
|
||||
/* 'z' changed to 'Z' --davidm 1/25/99 */
|
||||
|
||||
|
||||
for (str=buf ; *fmt ; ++fmt) {
|
||||
if (*fmt != '%') {
|
||||
*str++ = *fmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* process flags */
|
||||
flags = 0;
|
||||
repeat:
|
||||
++fmt; /* this also skips first '%' */
|
||||
switch (*fmt) {
|
||||
case '-': flags |= LEFT; goto repeat;
|
||||
case '+': flags |= PLUS; goto repeat;
|
||||
case ' ': flags |= SPACE; goto repeat;
|
||||
case '#': flags |= SPECIAL; goto repeat;
|
||||
case '0': flags |= ZEROPAD; goto repeat;
|
||||
}
|
||||
|
||||
/* get field width */
|
||||
field_width = -1;
|
||||
if ('0' <= *fmt && *fmt <= '9')
|
||||
field_width = skip_atoi(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
++fmt;
|
||||
/* it's the next argument */
|
||||
field_width = va_arg(args, int);
|
||||
if (field_width < 0) {
|
||||
field_width = -field_width;
|
||||
flags |= LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the precision */
|
||||
precision = -1;
|
||||
if (*fmt == '.') {
|
||||
++fmt;
|
||||
if ('0' <= *fmt && *fmt <= '9')
|
||||
precision = skip_atoi(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
++fmt;
|
||||
/* it's the next argument */
|
||||
precision = va_arg(args, int);
|
||||
}
|
||||
if (precision < 0)
|
||||
precision = 0;
|
||||
}
|
||||
|
||||
/* get the conversion qualifier */
|
||||
qualifier = -1;
|
||||
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
|
||||
qualifier = *fmt;
|
||||
++fmt;
|
||||
}
|
||||
|
||||
/* default base */
|
||||
base = 10;
|
||||
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
if (!(flags & LEFT))
|
||||
while (--field_width > 0)
|
||||
*str++ = ' ';
|
||||
*str++ = (unsigned char) va_arg(args, int);
|
||||
while (--field_width > 0)
|
||||
*str++ = ' ';
|
||||
continue;
|
||||
|
||||
case 's':
|
||||
s = va_arg(args, char *);
|
||||
if (!s)
|
||||
s = "<NULL>";
|
||||
|
||||
len = strnlen(s, precision);
|
||||
|
||||
if (!(flags & LEFT))
|
||||
while (len < field_width--)
|
||||
*str++ = ' ';
|
||||
for (i = 0; i < len; ++i)
|
||||
*str++ = *s++;
|
||||
while (len < field_width--)
|
||||
*str++ = ' ';
|
||||
continue;
|
||||
|
||||
case 'p':
|
||||
if (field_width == -1) {
|
||||
field_width = 2*sizeof(void *);
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
str = number(str,
|
||||
(unsigned long) va_arg(args, void *), 16,
|
||||
field_width, precision, flags);
|
||||
continue;
|
||||
|
||||
|
||||
case 'n':
|
||||
if (qualifier == 'l') {
|
||||
long * ip = va_arg(args, long *);
|
||||
*ip = (str - buf);
|
||||
} else if (qualifier == 'Z') {
|
||||
size_t * ip = va_arg(args, size_t *);
|
||||
*ip = (str - buf);
|
||||
} else {
|
||||
int * ip = va_arg(args, int *);
|
||||
*ip = (str - buf);
|
||||
}
|
||||
continue;
|
||||
|
||||
case '%':
|
||||
*str++ = '%';
|
||||
continue;
|
||||
|
||||
/* integer number formats - set up the flags and "break" */
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
flags |= LARGE;
|
||||
case 'x':
|
||||
base = 16;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
case 'u':
|
||||
break;
|
||||
|
||||
default:
|
||||
*str++ = '%';
|
||||
if (*fmt)
|
||||
*str++ = *fmt;
|
||||
else
|
||||
--fmt;
|
||||
continue;
|
||||
}
|
||||
if (qualifier == 'l') {
|
||||
num = va_arg(args, unsigned long);
|
||||
if (flags & SIGN)
|
||||
num = (signed long) num;
|
||||
} else if (qualifier == 'Z') {
|
||||
num = va_arg(args, size_t);
|
||||
} else if (qualifier == 'h') {
|
||||
num = (unsigned short) va_arg(args, int);
|
||||
if (flags & SIGN)
|
||||
num = (signed short) num;
|
||||
} else {
|
||||
num = va_arg(args, unsigned int);
|
||||
if (flags & SIGN)
|
||||
num = (signed int) num;
|
||||
}
|
||||
str = number(str, num, base, field_width, precision, flags);
|
||||
}
|
||||
*str = '\0';
|
||||
return str-buf;
|
||||
}
|
||||
|
||||
int sprintf(char * buf, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i=vsprintf(buf,fmt,args);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
||||
|
||||
static char sprint_buf[1024];
|
||||
|
||||
int
|
||||
printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int n;
|
||||
|
||||
va_start(args, fmt);
|
||||
n = vsprintf(sprint_buf, fmt, args);
|
||||
va_end(args);
|
||||
write(stdout, sprint_buf, n);
|
||||
return n;
|
||||
}
|
18
arch/powerpc/boot/prom.h
一般檔案
18
arch/powerpc/boot/prom.h
一般檔案
@@ -0,0 +1,18 @@
|
||||
#ifndef _PPC_BOOT_PROM_H_
|
||||
#define _PPC_BOOT_PROM_H_
|
||||
|
||||
extern int (*prom) (void *);
|
||||
extern void *chosen_handle;
|
||||
|
||||
extern void *stdin;
|
||||
extern void *stdout;
|
||||
extern void *stderr;
|
||||
|
||||
extern int write(void *handle, void *ptr, int nb);
|
||||
extern int read(void *handle, void *ptr, int nb);
|
||||
extern void exit(void);
|
||||
extern void pause(void);
|
||||
extern void *finddevice(const char *);
|
||||
extern void *claim(unsigned long virt, unsigned long size, unsigned long align);
|
||||
extern int getprop(void *phandle, const char *name, void *buf, int buflen);
|
||||
#endif /* _PPC_BOOT_PROM_H_ */
|
16
arch/powerpc/boot/stdio.h
一般檔案
16
arch/powerpc/boot/stdio.h
一般檔案
@@ -0,0 +1,16 @@
|
||||
#ifndef _PPC_BOOT_STDIO_H_
|
||||
#define _PPC_BOOT_STDIO_H_
|
||||
|
||||
extern int printf(const char *fmt, ...);
|
||||
|
||||
extern int sprintf(char *buf, const char *fmt, ...);
|
||||
|
||||
extern int vsprintf(char *buf, const char *fmt, va_list args);
|
||||
|
||||
extern int putc(int c, void *f);
|
||||
extern int putchar(int c);
|
||||
extern int getchar(void);
|
||||
|
||||
extern int fputs(char *str, void *f);
|
||||
|
||||
#endif /* _PPC_BOOT_STDIO_H_ */
|
216
arch/powerpc/boot/string.S
一般檔案
216
arch/powerpc/boot/string.S
一般檔案
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) Paul Mackerras 1997.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* NOTE: this code runs in 32 bit mode and is packaged as ELF32.
|
||||
*/
|
||||
|
||||
#include "ppc_asm.h"
|
||||
|
||||
.text
|
||||
.globl strcpy
|
||||
strcpy:
|
||||
addi r5,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
stbu r0,1(r5)
|
||||
bne 1b
|
||||
blr
|
||||
|
||||
.globl strncpy
|
||||
strncpy:
|
||||
cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
addi r6,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
stbu r0,1(r6)
|
||||
bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
|
||||
blr
|
||||
|
||||
.globl strcat
|
||||
strcat:
|
||||
addi r5,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r0,1(r5)
|
||||
cmpwi 0,r0,0
|
||||
bne 1b
|
||||
addi r5,r5,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
stbu r0,1(r5)
|
||||
bne 1b
|
||||
blr
|
||||
|
||||
.globl strcmp
|
||||
strcmp:
|
||||
addi r5,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r3,1(r5)
|
||||
cmpwi 1,r3,0
|
||||
lbzu r0,1(r4)
|
||||
subf. r3,r0,r3
|
||||
beqlr 1
|
||||
beq 1b
|
||||
blr
|
||||
|
||||
.globl strlen
|
||||
strlen:
|
||||
addi r4,r3,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
bne 1b
|
||||
subf r3,r3,r4
|
||||
blr
|
||||
|
||||
.globl memset
|
||||
memset:
|
||||
rlwimi r4,r4,8,16,23
|
||||
rlwimi r4,r4,16,0,15
|
||||
addi r6,r3,-4
|
||||
cmplwi 0,r5,4
|
||||
blt 7f
|
||||
stwu r4,4(r6)
|
||||
beqlr
|
||||
andi. r0,r6,3
|
||||
add r5,r0,r5
|
||||
subf r6,r0,r6
|
||||
rlwinm r0,r5,32-2,2,31
|
||||
mtctr r0
|
||||
bdz 6f
|
||||
1: stwu r4,4(r6)
|
||||
bdnz 1b
|
||||
6: andi. r5,r5,3
|
||||
7: cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
addi r6,r6,3
|
||||
8: stbu r4,1(r6)
|
||||
bdnz 8b
|
||||
blr
|
||||
|
||||
.globl memmove
|
||||
memmove:
|
||||
cmplw 0,r3,r4
|
||||
bgt backwards_memcpy
|
||||
/* fall through */
|
||||
|
||||
.globl memcpy
|
||||
memcpy:
|
||||
rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */
|
||||
addi r6,r3,-4
|
||||
addi r4,r4,-4
|
||||
beq 2f /* if less than 8 bytes to do */
|
||||
andi. r0,r6,3 /* get dest word aligned */
|
||||
mtctr r7
|
||||
bne 5f
|
||||
1: lwz r7,4(r4)
|
||||
lwzu r8,8(r4)
|
||||
stw r7,4(r6)
|
||||
stwu r8,8(r6)
|
||||
bdnz 1b
|
||||
andi. r5,r5,7
|
||||
2: cmplwi 0,r5,4
|
||||
blt 3f
|
||||
lwzu r0,4(r4)
|
||||
addi r5,r5,-4
|
||||
stwu r0,4(r6)
|
||||
3: cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
addi r4,r4,3
|
||||
addi r6,r6,3
|
||||
4: lbzu r0,1(r4)
|
||||
stbu r0,1(r6)
|
||||
bdnz 4b
|
||||
blr
|
||||
5: subfic r0,r0,4
|
||||
mtctr r0
|
||||
6: lbz r7,4(r4)
|
||||
addi r4,r4,1
|
||||
stb r7,4(r6)
|
||||
addi r6,r6,1
|
||||
bdnz 6b
|
||||
subf r5,r0,r5
|
||||
rlwinm. r7,r5,32-3,3,31
|
||||
beq 2b
|
||||
mtctr r7
|
||||
b 1b
|
||||
|
||||
.globl backwards_memcpy
|
||||
backwards_memcpy:
|
||||
rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */
|
||||
add r6,r3,r5
|
||||
add r4,r4,r5
|
||||
beq 2f
|
||||
andi. r0,r6,3
|
||||
mtctr r7
|
||||
bne 5f
|
||||
1: lwz r7,-4(r4)
|
||||
lwzu r8,-8(r4)
|
||||
stw r7,-4(r6)
|
||||
stwu r8,-8(r6)
|
||||
bdnz 1b
|
||||
andi. r5,r5,7
|
||||
2: cmplwi 0,r5,4
|
||||
blt 3f
|
||||
lwzu r0,-4(r4)
|
||||
subi r5,r5,4
|
||||
stwu r0,-4(r6)
|
||||
3: cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
4: lbzu r0,-1(r4)
|
||||
stbu r0,-1(r6)
|
||||
bdnz 4b
|
||||
blr
|
||||
5: mtctr r0
|
||||
6: lbzu r7,-1(r4)
|
||||
stbu r7,-1(r6)
|
||||
bdnz 6b
|
||||
subf r5,r0,r5
|
||||
rlwinm. r7,r5,32-3,3,31
|
||||
beq 2b
|
||||
mtctr r7
|
||||
b 1b
|
||||
|
||||
.globl memcmp
|
||||
memcmp:
|
||||
cmpwi 0,r5,0
|
||||
blelr
|
||||
mtctr r5
|
||||
addi r6,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r3,1(r6)
|
||||
lbzu r0,1(r4)
|
||||
subf. r3,r0,r3
|
||||
bdnzt 2,1b
|
||||
blr
|
||||
|
||||
|
||||
/*
|
||||
* Flush the dcache and invalidate the icache for a range of addresses.
|
||||
*
|
||||
* flush_cache(addr, len)
|
||||
*/
|
||||
.global flush_cache
|
||||
flush_cache:
|
||||
addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */
|
||||
rlwinm. 4,4,27,5,31
|
||||
mtctr 4
|
||||
beqlr
|
||||
1: dcbf 0,3
|
||||
icbi 0,3
|
||||
addi 3,3,0x20
|
||||
bdnz 1b
|
||||
sync
|
||||
isync
|
||||
blr
|
||||
|
17
arch/powerpc/boot/string.h
一般檔案
17
arch/powerpc/boot/string.h
一般檔案
@@ -0,0 +1,17 @@
|
||||
#ifndef _PPC_BOOT_STRING_H_
|
||||
#define _PPC_BOOT_STRING_H_
|
||||
#include <stddef.h>
|
||||
|
||||
extern char *strcpy(char *dest, const char *src);
|
||||
extern char *strncpy(char *dest, const char *src, size_t n);
|
||||
extern char *strcat(char *dest, const char *src);
|
||||
extern int strcmp(const char *s1, const char *s2);
|
||||
extern size_t strlen(const char *s);
|
||||
extern size_t strnlen(const char *s, size_t count);
|
||||
|
||||
extern void *memset(void *s, int c, size_t n);
|
||||
extern void *memmove(void *dest, const void *src, unsigned long n);
|
||||
extern void *memcpy(void *dest, const void *src, unsigned long n);
|
||||
extern int memcmp(const void *s1, const void *s2, size_t n);
|
||||
|
||||
#endif /* _PPC_BOOT_STRING_H_ */
|
46
arch/powerpc/boot/zImage.lds
一般檔案
46
arch/powerpc/boot/zImage.lds
一般檔案
@@ -0,0 +1,46 @@
|
||||
OUTPUT_ARCH(powerpc:common)
|
||||
ENTRY(_zimage_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = (4*1024*1024);
|
||||
_start = .;
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.fixup)
|
||||
}
|
||||
_etext = .;
|
||||
. = ALIGN(4096);
|
||||
.data :
|
||||
{
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
__got2_start = .;
|
||||
*(.got2)
|
||||
__got2_end = .;
|
||||
}
|
||||
|
||||
. = ALIGN(4096);
|
||||
_vmlinux_start = .;
|
||||
.kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
|
||||
_vmlinux_end = .;
|
||||
|
||||
. = ALIGN(4096);
|
||||
_initrd_start = .;
|
||||
.kernel:initrd : { *(.kernel:initrd) }
|
||||
_initrd_end = .;
|
||||
|
||||
. = ALIGN(4096);
|
||||
_edata = .;
|
||||
|
||||
. = ALIGN(4096);
|
||||
__bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.sbss)
|
||||
*(.bss)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
_end = . ;
|
||||
}
|
新增問題並參考
封鎖使用者