diff options
Diffstat (limited to 'stand/powerpc')
56 files changed, 7453 insertions, 0 deletions
diff --git a/stand/powerpc/Makefile b/stand/powerpc/Makefile new file mode 100644 index 000000000000..969eee8dc63e --- /dev/null +++ b/stand/powerpc/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.include <bsd.init.mk> + +SUBDIR= boot1.chrp ofw uboot +.if ${MACHINE_ARCH} != "powerpcspe" +SUBDIR+= ps3 +.endif +.if ${MK_FDT} == "yes" +SUBDIR+= kboot +.endif + +.include <bsd.subdir.mk> diff --git a/stand/powerpc/Makefile.inc b/stand/powerpc/Makefile.inc new file mode 100644 index 000000000000..265f86d1ed55 --- /dev/null +++ b/stand/powerpc/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include "../Makefile.inc" diff --git a/stand/powerpc/boot1.chrp/Makefile b/stand/powerpc/boot1.chrp/Makefile new file mode 100644 index 000000000000..384d0abc2788 --- /dev/null +++ b/stand/powerpc/boot1.chrp/Makefile @@ -0,0 +1,42 @@ +# $FreeBSD$ + +.include <bsd.init.mk> + +SSP_CFLAGS= + +PROG= boot1.elf +NEWVERSWHAT= "Open Firmware boot block" ${MACHINE_ARCH} +INSTALLFLAGS= -b + +FILES= boot1.hfs +SRCS= boot1.c ashldi3.c syncicache.c + +MAN= + +CFLAGS= -ffreestanding -msoft-float \ + -I${LDRSRC} -I${SYSDIR} -I${SASRC} \ + -D_STANDALONE +LDFLAGS=-nostdlib -static -Wl,-N + +.PATH: ${SYSDIR}/libkern ${SRCTOP}/lib/libc/powerpc/gen ${.CURDIR} + +# The following inserts out objects into a template HFS +# created by generate-hfs.sh + +.include "${.CURDIR}/Makefile.hfs" + +boot1.hfs: boot1.elf bootinfo.txt + echo ${.OBJDIR} + uudecode ${.CURDIR}/hfs.tmpl.bz2.uu + mv hfs.tmpl.bz2 ${.TARGET}.bz2 + bzip2 -f -d ${.TARGET}.bz2 + ${DD} if=boot1.elf of=${.TARGET} seek=${BOOT1_OFFSET} conv=notrunc + ${DD} if=${.CURDIR}/bootinfo.txt of=${.TARGET} seek=${BOOTINFO_OFFSET} \ + conv=notrunc + +CLEANFILES+= boot1.hfs + +boot1.o: ${SASRC}/ufsread.c + +.include <bsd.prog.mk> + diff --git a/stand/powerpc/boot1.chrp/Makefile.hfs b/stand/powerpc/boot1.chrp/Makefile.hfs new file mode 100644 index 000000000000..c6c2d866f6bf --- /dev/null +++ b/stand/powerpc/boot1.chrp/Makefile.hfs @@ -0,0 +1,4 @@ +# This file autogenerated by generate-hfs.sh - DO NOT EDIT +# $FreeBSD$ +BOOTINFO_OFFSET=0x9c +BOOT1_OFFSET=0x1c diff --git a/stand/powerpc/boot1.chrp/boot1.c b/stand/powerpc/boot1.chrp/boot1.c new file mode 100644 index 000000000000..8de8e9f17f41 --- /dev/null +++ b/stand/powerpc/boot1.chrp/boot1.c @@ -0,0 +1,777 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * Copyright (c) 2001 Robert Drehmel + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/dirent.h> +#include <machine/elf.h> +#include <machine/stdarg.h> + +#include "paths.h" + +#define BSIZEMAX 16384 + +typedef int putc_func_t(char c, void *arg); +typedef int32_t ofwh_t; + +struct sp_data { + char *sp_buf; + u_int sp_len; + u_int sp_size; +}; + +static const char digits[] = "0123456789abcdef"; + +static char bootpath[128]; +static char bootargs[128]; + +static ofwh_t bootdev; + +static struct fs fs; +static char blkbuf[BSIZEMAX]; +static unsigned int fsblks; + +static uint32_t fs_off; + +int main(int ac, char **av); + +static void exit(int) __dead2; +static void load(const char *); +static int dskread(void *, u_int64_t, int); + +static void usage(void); + +static void bcopy(const void *src, void *dst, size_t len); +static void bzero(void *b, size_t len); + +static int domount(const char *device, int quiet); + +static void panic(const char *fmt, ...) __dead2; +static int printf(const char *fmt, ...); +static int putchar(char c, void *arg); +static int vprintf(const char *fmt, va_list ap); +static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); + +static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); +static int __putc(char c, void *arg); +static int __puts(const char *s, putc_func_t *putc, void *arg); +static int __sputc(char c, void *arg); +static char *__uitoa(char *buf, u_int val, int base); +static char *__ultoa(char *buf, u_long val, int base); + +void __syncicache(void *, int); + +/* + * Open Firmware interface functions + */ +typedef u_int32_t ofwcell_t; +typedef u_int32_t u_ofwh_t; +typedef int (*ofwfp_t)(void *); +ofwfp_t ofw; /* the prom Open Firmware entry */ +ofwh_t chosenh; + +void ofw_init(void *, int, int (*)(void *), char *, int); +static ofwh_t ofw_finddevice(const char *); +static ofwh_t ofw_open(const char *); +static int ofw_close(ofwh_t); +static int ofw_getprop(ofwh_t, const char *, void *, size_t); +static int ofw_setprop(ofwh_t, const char *, void *, size_t); +static int ofw_read(ofwh_t, void *, size_t); +static int ofw_write(ofwh_t, const void *, size_t); +static int ofw_claim(void *virt, size_t len, u_int align); +static int ofw_seek(ofwh_t, u_int64_t); +static void ofw_exit(void) __dead2; + +ofwh_t bootdevh; +ofwh_t stdinh, stdouth; + +__asm(" \n\ + .data \n\ + .align 4 \n\ +stack: \n\ + .space 16384 \n\ + \n\ + .text \n\ + .globl _start \n\ +_start: \n\ + lis %r1,stack@ha \n\ + addi %r1,%r1,stack@l \n\ + addi %r1,%r1,8192 \n\ + \n\ + b ofw_init \n\ +"); + +void +ofw_init(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl) +{ + char *av[16]; + char *p; + int ac; + + ofw = openfirm; + + chosenh = ofw_finddevice("/chosen"); + ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); + ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); + ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs)); + ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); + + bootargs[sizeof(bootargs) - 1] = '\0'; + bootpath[sizeof(bootpath) - 1] = '\0'; + + p = bootpath; + while (*p != '\0') { + /* Truncate partition ID */ + if (*p == ':') { + ofw_close(bootdev); + *(++p) = '\0'; + break; + } + p++; + } + + ac = 0; + p = bootargs; + for (;;) { + while (*p == ' ' && *p != '\0') + p++; + if (*p == '\0' || ac >= 16) + break; + av[ac++] = p; + while (*p != ' ' && *p != '\0') + p++; + if (*p != '\0') + *p++ = '\0'; + } + + exit(main(ac, av)); +} + +static ofwh_t +ofw_finddevice(const char *name) +{ + ofwcell_t args[] = { + (ofwcell_t)"finddevice", + 1, + 1, + (ofwcell_t)name, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_finddevice: name=\"%s\"\n", name); + return (1); + } + return (args[4]); +} + +static int +ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) +{ + ofwcell_t args[] = { + (ofwcell_t)"getprop", + 4, + 1, + (u_ofwh_t)ofwh, + (ofwcell_t)name, + (ofwcell_t)buf, + len, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", + ofwh, buf, len); + return (1); + } + return (0); +} + +static int +ofw_setprop(ofwh_t ofwh, const char *name, void *buf, size_t len) +{ + ofwcell_t args[] = { + (ofwcell_t)"setprop", + 4, + 1, + (u_ofwh_t)ofwh, + (ofwcell_t)name, + (ofwcell_t)buf, + len, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_setprop: ofwh=0x%x buf=%p len=%u\n", + ofwh, buf, len); + return (1); + } + return (0); +} + +static ofwh_t +ofw_open(const char *path) +{ + ofwcell_t args[] = { + (ofwcell_t)"open", + 1, + 1, + (ofwcell_t)path, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_open: path=\"%s\"\n", path); + return (-1); + } + return (args[4]); +} + +static int +ofw_close(ofwh_t devh) +{ + ofwcell_t args[] = { + (ofwcell_t)"close", + 1, + 0, + (u_ofwh_t)devh + }; + + if ((*ofw)(args)) { + printf("ofw_close: devh=0x%x\n", devh); + return (1); + } + return (0); +} + +static int +ofw_claim(void *virt, size_t len, u_int align) +{ + ofwcell_t args[] = { + (ofwcell_t)"claim", + 3, + 1, + (ofwcell_t)virt, + len, + align, + 0, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_claim: virt=%p len=%u\n", virt, len); + return (1); + } + + return (0); +} + +static int +ofw_read(ofwh_t devh, void *buf, size_t len) +{ + ofwcell_t args[] = { + (ofwcell_t)"read", + 3, + 1, + (u_ofwh_t)devh, + (ofwcell_t)buf, + len, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); + return (1); + } + return (0); +} + +static int +ofw_write(ofwh_t devh, const void *buf, size_t len) +{ + ofwcell_t args[] = { + (ofwcell_t)"write", + 3, + 1, + (u_ofwh_t)devh, + (ofwcell_t)buf, + len, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); + return (1); + } + return (0); +} + +static int +ofw_seek(ofwh_t devh, u_int64_t off) +{ + ofwcell_t args[] = { + (ofwcell_t)"seek", + 3, + 1, + (u_ofwh_t)devh, + off >> 32, + off, + 0 + }; + + if ((*ofw)(args)) { + printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); + return (1); + } + return (0); +} + +static void +ofw_exit(void) +{ + ofwcell_t args[3]; + + args[0] = (ofwcell_t)"exit"; + args[1] = 0; + args[2] = 0; + + for (;;) + (*ofw)(args); +} + +static void +bcopy(const void *src, void *dst, size_t len) +{ + const char *s = src; + char *d = dst; + + while (len-- != 0) + *d++ = *s++; +} + +static void +memcpy(void *dst, const void *src, size_t len) +{ + bcopy(src, dst, len); +} + +static void +bzero(void *b, size_t len) +{ + char *p = b; + + while (len-- != 0) + *p++ = 0; +} + +static int +strcmp(const char *s1, const char *s2) +{ + for (; *s1 == *s2 && *s1; s1++, s2++) + ; + return ((u_char)*s1 - (u_char)*s2); +} + +#include "ufsread.c" + +int +main(int ac, char **av) +{ + const char *path; + char bootpath_full[255]; + int i, len; + + path = PATH_LOADER; + for (i = 0; i < ac; i++) { + switch (av[i][0]) { + case '-': + switch (av[i][1]) { + default: + usage(); + } + break; + default: + path = av[i]; + break; + } + } + + printf(" \n>> FreeBSD/powerpc Open Firmware boot block\n" + " Boot path: %s\n" + " Boot loader: %s\n", bootpath, path); + + len = 0; + while (bootpath[len] != '\0') len++; + + memcpy(bootpath_full,bootpath,len+1); + + if (bootpath_full[len-1] != ':') { + /* First try full volume */ + if (domount(bootpath_full,1) == 0) + goto out; + + /* Add a : so that we try partitions if that fails */ + if (bootdev > 0) + ofw_close(bootdev); + bootpath_full[len] = ':'; + len += 1; + } + + /* Loop through first 16 partitions to find a UFS one */ + for (i = 0; i < 16; i++) { + if (i < 10) { + bootpath_full[len] = i + '0'; + bootpath_full[len+1] = '\0'; + } else { + bootpath_full[len] = '1'; + bootpath_full[len+1] = i - 10 + '0'; + bootpath_full[len+2] = '\0'; + } + + if (domount(bootpath_full,1) >= 0) + break; + + if (bootdev > 0) + ofw_close(bootdev); + } + + if (i >= 16) + panic("domount"); + +out: + printf(" Boot volume: %s\n",bootpath_full); + ofw_setprop(chosenh, "bootargs", bootpath_full, len+2); + load(path); + return (1); +} + +static void +usage(void) +{ + + printf("usage: boot device [/path/to/loader]\n"); + exit(1); +} + +static void +exit(int code) +{ + + ofw_exit(); +} + +static struct dmadat __dmadat; + +static int +domount(const char *device, int quiet) +{ + + dmadat = &__dmadat; + if ((bootdev = ofw_open(device)) == -1) { + printf("domount: can't open device\n"); + return (-1); + } + if (fsread(0, NULL, 0)) { + if (!quiet) + printf("domount: can't read superblock\n"); + return (-1); + } + return (0); +} + +static void +load(const char *fname) +{ + Elf32_Ehdr eh; + Elf32_Phdr ph; + caddr_t p; + ufs_ino_t ino; + int i; + + if ((ino = lookup(fname)) == 0) { + printf("File %s not found\n", fname); + return; + } + if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { + printf("Can't read elf header\n"); + return; + } + if (!IS_ELF(eh)) { + printf("Not an ELF file\n"); + return; + } + for (i = 0; i < eh.e_phnum; i++) { + fs_off = eh.e_phoff + i * eh.e_phentsize; + if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { + printf("Can't read program header %d\n", i); + return; + } + if (ph.p_type != PT_LOAD) + continue; + fs_off = ph.p_offset; + p = (caddr_t)ph.p_vaddr; + ofw_claim(p,(ph.p_filesz > ph.p_memsz) ? + ph.p_filesz : ph.p_memsz,0); + if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { + printf("Can't read content of section %d\n", i); + return; + } + if (ph.p_filesz != ph.p_memsz) + bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); + __syncicache(p, ph.p_memsz); + } + ofw_close(bootdev); + (*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0, + ofw,NULL,0); +} + +static int +dskread(void *buf, u_int64_t lba, int nblk) +{ + /* + * The Open Firmware should open the correct partition for us. + * That means, if we read from offset zero on an open instance handle, + * we should read from offset zero of that partition. + */ + ofw_seek(bootdev, lba * DEV_BSIZE); + ofw_read(bootdev, buf, nblk * DEV_BSIZE); + return (0); +} + +static void +panic(const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof buf, fmt, ap); + printf("panic: %s\n", buf); + va_end(ap); + + exit(1); +} + +static int +printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vprintf(fmt, ap); + va_end(ap); + return (ret); +} + +static int +putchar(char c, void *arg) +{ + char buf; + + if (c == '\n') { + buf = '\r'; + ofw_write(stdouth, &buf, 1); + } + buf = c; + ofw_write(stdouth, &buf, 1); + return (1); +} + +static int +vprintf(const char *fmt, va_list ap) +{ + int ret; + + ret = __printf(fmt, putchar, 0, ap); + return (ret); +} + +static int +vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) +{ + struct sp_data sp; + int ret; + + sp.sp_buf = str; + sp.sp_len = 0; + sp.sp_size = sz; + ret = __printf(fmt, __sputc, &sp, ap); + return (ret); +} + +static int +__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) +{ + char buf[(sizeof(long) * 8) + 1]; + char *nbuf; + u_long ul; + u_int ui; + int lflag; + int sflag; + char *s; + int pad; + int ret; + int c; + + nbuf = &buf[sizeof buf - 1]; + ret = 0; + while ((c = *fmt++) != 0) { + if (c != '%') { + ret += putc(c, arg); + continue; + } + lflag = 0; + sflag = 0; + pad = 0; +reswitch: c = *fmt++; + switch (c) { + case '#': + sflag = 1; + goto reswitch; + case '%': + ret += putc('%', arg); + break; + case 'c': + c = va_arg(ap, int); + ret += putc(c, arg); + break; + case 'd': + if (lflag == 0) { + ui = (u_int)va_arg(ap, int); + if (ui < (int)ui) { + ui = -ui; + ret += putc('-', arg); + } + s = __uitoa(nbuf, ui, 10); + } else { + ul = (u_long)va_arg(ap, long); + if (ul < (long)ul) { + ul = -ul; + ret += putc('-', arg); + } + s = __ultoa(nbuf, ul, 10); + } + ret += __puts(s, putc, arg); + break; + case 'l': + lflag = 1; + goto reswitch; + case 'o': + if (lflag == 0) { + ui = (u_int)va_arg(ap, u_int); + s = __uitoa(nbuf, ui, 8); + } else { + ul = (u_long)va_arg(ap, u_long); + s = __ultoa(nbuf, ul, 8); + } + ret += __puts(s, putc, arg); + break; + case 'p': + ul = (u_long)va_arg(ap, void *); + s = __ultoa(nbuf, ul, 16); + ret += __puts("0x", putc, arg); + ret += __puts(s, putc, arg); + break; + case 's': + s = va_arg(ap, char *); + ret += __puts(s, putc, arg); + break; + case 'u': + if (lflag == 0) { + ui = va_arg(ap, u_int); + s = __uitoa(nbuf, ui, 10); + } else { + ul = va_arg(ap, u_long); + s = __ultoa(nbuf, ul, 10); + } + ret += __puts(s, putc, arg); + break; + case 'x': + if (lflag == 0) { + ui = va_arg(ap, u_int); + s = __uitoa(nbuf, ui, 16); + } else { + ul = va_arg(ap, u_long); + s = __ultoa(nbuf, ul, 16); + } + if (sflag) + ret += __puts("0x", putc, arg); + ret += __puts(s, putc, arg); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + pad = pad * 10 + c - '0'; + goto reswitch; + default: + break; + } + } + return (ret); +} + +static int +__sputc(char c, void *arg) +{ + struct sp_data *sp; + + sp = arg; + if (sp->sp_len < sp->sp_size) + sp->sp_buf[sp->sp_len++] = c; + sp->sp_buf[sp->sp_len] = '\0'; + return (1); +} + +static int +__puts(const char *s, putc_func_t *putc, void *arg) +{ + const char *p; + int ret; + + ret = 0; + for (p = s; *p != '\0'; p++) + ret += putc(*p, arg); + return (ret); +} + +static char * +__uitoa(char *buf, u_int ui, int base) +{ + char *p; + + p = buf; + *p = '\0'; + do + *--p = digits[ui % base]; + while ((ui /= base) != 0); + return (p); +} + +static char * +__ultoa(char *buf, u_long ul, int base) +{ + char *p; + + p = buf; + *p = '\0'; + do + *--p = digits[ul % base]; + while ((ul /= base) != 0); + return (p); +} diff --git a/stand/powerpc/boot1.chrp/bootinfo.txt b/stand/powerpc/boot1.chrp/bootinfo.txt new file mode 100644 index 000000000000..61cf0079fa6f --- /dev/null +++ b/stand/powerpc/boot1.chrp/bootinfo.txt @@ -0,0 +1,14 @@ +<CHRP-BOOT> +<DESCRIPTION>FreeBSD/powerpc bootloader</DESCRIPTION> +<OS-NAME>FreeBSD</OS-NAME> +<VERSION> $FreeBSD$ </VERSION> + +<COMPATIBLE> +MacRISC MacRISC3 MacRISC4 +</COMPATIBLE> +<BOOT-SCRIPT> +" screen" output +boot &device;:&partition;,\ppc\boot1.elf +</BOOT-SCRIPT> +</CHRP-BOOT> + diff --git a/stand/powerpc/boot1.chrp/generate-hfs.sh b/stand/powerpc/boot1.chrp/generate-hfs.sh new file mode 100755 index 000000000000..ef368d1566b4 --- /dev/null +++ b/stand/powerpc/boot1.chrp/generate-hfs.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +# This script generates the dummy HFS filesystem used for the PowerPC boot +# blocks. It uses hfsutils (emulators/hfsutils) to generate a template +# filesystem with the relevant interesting files. These are then found by +# grep, and the offsets written to a Makefile snippet. +# +# Because of licensing concerns, and because it is overkill, we do not +# distribute hfsutils as a build tool. If you need to regenerate the HFS +# template (e.g. because the boot block or the CHRP script have grown), +# you must install it from ports. + +# $FreeBSD$ + +HFS_SIZE=1600 #Size in 512-byte blocks of the produced image + +CHRPBOOT_SIZE=2k +BOOT1_SIZE=64k + +# Generate 800K HFS image +OUTPUT_FILE=hfs.tmpl + +dd if=/dev/zero of=$OUTPUT_FILE bs=512 count=$HFS_SIZE +hformat -l "FreeBSD Bootstrap" $OUTPUT_FILE +hmount $OUTPUT_FILE + +# Create and bless a directory for the boot loader +hmkdir ppc +hattrib -b ppc +hcd ppc + +# Make two dummy files for the CHRP boot script and boot1 +echo 'Bootinfo START' | dd of=bootinfo.txt.tmp cbs=$CHRPBOOT_SIZE count=1 conv=block +echo 'Boot1 START' | dd of=boot1.elf.tmp cbs=$BOOT1_SIZE count=1 conv=block + +hcopy boot1.elf.tmp :boot1.elf +hcopy bootinfo.txt.tmp :bootinfo.txt +hattrib -c chrp -t tbxi bootinfo.txt +humount + +rm bootinfo.txt.tmp +rm boot1.elf.tmp + +# Locate the offsets of the two fake files +BOOTINFO_OFFSET=$(hd $OUTPUT_FILE | grep 'Bootinfo START' | cut -f 1 -d ' ') +BOOT1_OFFSET=$(hd $OUTPUT_FILE | grep 'Boot1 START' | cut -f 1 -d ' ') + +# Convert to numbers of blocks +BOOTINFO_OFFSET=$(echo 0x$BOOTINFO_OFFSET | awk '{printf("%x\n",$1/512);}') +BOOT1_OFFSET=$(echo 0x$BOOT1_OFFSET | awk '{printf("%x\n",$1/512);}') + +echo '# This file autogenerated by generate-hfs.sh - DO NOT EDIT' > Makefile.hfs +echo '# $FreeBSD$' >> Makefile.hfs +echo "BOOTINFO_OFFSET=0x$BOOTINFO_OFFSET" >> Makefile.hfs +echo "BOOT1_OFFSET=0x$BOOT1_OFFSET" >> Makefile.hfs + +bzip2 $OUTPUT_FILE +echo 'HFS template boot filesystem created by generate-hfs.sh' > $OUTPUT_FILE.bz2.uu +echo 'DO NOT EDIT' >> $OUTPUT_FILE.bz2.uu +echo '$FreeBSD$' >> $OUTPUT_FILE.bz2.uu + +uuencode $OUTPUT_FILE.bz2 $OUTPUT_FILE.bz2 >> $OUTPUT_FILE.bz2.uu +rm $OUTPUT_FILE.bz2 + diff --git a/stand/powerpc/boot1.chrp/hfs.tmpl.bz2.uu b/stand/powerpc/boot1.chrp/hfs.tmpl.bz2.uu new file mode 100644 index 000000000000..20b7695e6db4 --- /dev/null +++ b/stand/powerpc/boot1.chrp/hfs.tmpl.bz2.uu @@ -0,0 +1,18 @@ +HFS template boot filesystem created by generate-hfs.sh +DO NOT EDIT +$FreeBSD$ +begin 644 hfs.tmpl.bz2 +M0EIH.3%!629365^MV6L``"]__O___M)20>!0O2$>0#MUW$!$``%%$``@``!` +M!`!R2<`![@H2"2A2-Z)-HC]4`:`-``T:&@&@#0/TTH<`PC":8A@$`R`&$:9, +MF$8"&AP#",)IB&`0#(`81IDR81@(:")0HT*>4,:0TT`:!ZC0/*/4/1&@;4>H +M&@RYG-FL-,\=C91FTSS@99`O+OA;*$ZN3-&UF`W@#SP:;MVF_EN,-]P$ZN2B +M=";7YHA7VT!#<@,B`H*?S#?Q;CUJ8H8+9:E)+4"L7'CL5&D.IO4;H98%^4@[ +M9`*L&1``5*0#A(E<M\J&(@6BZXC<0K!#!)!H05`5*L!^DNM12_"L`<9!Y.7T +M<I94[[MT$^$30P-DYBVI.X7R<KY7&H$DA(<S;NW1PB7-47*Q>B8BH`S'1O^N +M)Y6'!#N:*:<E!+,#/,\;M_FXRP![+P44D6],L'G1X7Q&[JI6WN@&KCIW8:". +MTP=Y77`%67""`=I/UR500#!=DD+!>JYTEX\:%'"?.G$FCP8TM_0/ND`^IG3[ +M.QUEDP&P>3+Z442Q!:S.A1>00]'X'D%)UX9QZ>$Q?(808QB-4%9BBTL"L(BB +MEJ*'HH820Q$'%G':JF.:>$U4H`0S`:GSZM-C5BNX(2&$B"J*45`"4FEZ__%W +))%.%"07ZW9:P +` +end diff --git a/stand/powerpc/kboot/Makefile b/stand/powerpc/kboot/Makefile new file mode 100644 index 000000000000..bed586e6732a --- /dev/null +++ b/stand/powerpc/kboot/Makefile @@ -0,0 +1,50 @@ +# $FreeBSD$ + +LOADER_CD9660_SUPPORT?= yes +LOADER_MSDOS_SUPPORT?= no +LOADER_EXT2FS_SUPPORT?= yes +LOADER_UFS_SUPPORT?= yes +LOADER_NET_SUPPORT?= yes +LOADER_NFS_SUPPORT?= yes +LOADER_TFTP_SUPPORT?= no +LOADER_GZIP_SUPPORT?= yes +LOADER_BZIP2_SUPPORT?= no + +.include <bsd.init.mk> +MK_SSP= no +MAN= + +PROG= loader.kboot +NEWVERSWHAT= "kboot loader" ${MACHINE_ARCH} +INSTALLFLAGS= -b + +# Architecture-specific loader code +SRCS= conf.c metadata.c vers.c main.c ppc64_elf_freebsd.c +SRCS+= host_syscall.S hostcons.c hostdisk.c kerneltramp.S kbootfdt.c +SRCS+= ucmpdi2.c + +.include "${BOOTSRC}/fdt.mk" + +CFLAGS+= -mcpu=powerpc64 + +# Always add MI sources +HELP_FILES= # Disable +.include "${BOOTSRC}/loader.mk" +.PATH: ${SYSDIR}/libkern + +CFLAGS+= -Wall -ffreestanding -msoft-float -DAIM +# load address. set in linker script +RELOC?= 0x0 +CFLAGS+= -DRELOC=${RELOC} + +LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.powerpc + +# 64-bit bridge extensions +CFLAGS+= -Wa,-mppc64bridge + +DPADD= ${LIBFICL} ${LIBOFW} ${LIBFDT} ${LIBSA} +LDADD= ${LIBFICL} ${LIBOFW} ${LIBFDT} ${LIBSA} + +HELP_FILES+= ${FDTSRC}/help.fdt + +.include <bsd.prog.mk> diff --git a/stand/powerpc/kboot/conf.c b/stand/powerpc/kboot/conf.c new file mode 100644 index 000000000000..104dd93ca2fb --- /dev/null +++ b/stand/powerpc/kboot/conf.c @@ -0,0 +1,117 @@ +/*- + * Copyright (C) 1999 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "bootstrap.h" + +#if defined(LOADER_NET_SUPPORT) +#include "dev_net.h" +#endif + +extern struct devsw hostdisk; + +/* + * We could use linker sets for some or all of these, but + * then we would have to control what ended up linked into + * the bootstrap. So it's easier to conditionalise things + * here. + * + * XXX rename these arrays to be consistent and less namespace-hostile + */ + +/* Exported for libstand */ +struct devsw *devsw[] = { +#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT) + &hostdisk, +#endif +#if defined(LOADER_NET_SUPPORT) + &netdev, +#endif + NULL +}; + +struct fs_ops *file_system[] = { +#if defined(LOADER_UFS_SUPPORT) + &ufs_fsops, +#endif +#if defined(LOADER_CD9660_SUPPORT) + &cd9660_fsops, +#endif +#if defined(LOADER_EXT2FS_SUPPORT) + &ext2fs_fsops, +#endif +#if defined(LOADER_NFS_SUPPORT) + &nfs_fsops, +#endif +#if defined(LOADER_TFTP_SUPPORT) + &tftp_fsops, +#endif +#if defined(LOADER_GZIP_SUPPORT) + &gzipfs_fsops, +#endif +#if defined(LOADER_BZIP2_SUPPORT) + &bzipfs_fsops, +#endif + NULL +}; + +extern struct netif_driver kbootnet; + +struct netif_driver *netif_drivers[] = { +#if 0 /* XXX */ +#if defined(LOADER_NET_SUPPORT) + &kbootnet, +#endif +#endif + NULL, +}; + +/* Exported for PowerPC only */ +/* + * Sort formats so that those that can detect based on arguments + * rather than reading the file go first. + */ + +extern struct file_format ppc_elf64; + +struct file_format *file_formats[] = { + &ppc_elf64, + NULL +}; + +/* + * Consoles + */ +extern struct console hostconsole; + +struct console *consoles[] = { + &hostconsole, + NULL +}; + diff --git a/stand/powerpc/kboot/host_syscall.S b/stand/powerpc/kboot/host_syscall.S new file mode 100644 index 000000000000..3607fdb0d2a1 --- /dev/null +++ b/stand/powerpc/kboot/host_syscall.S @@ -0,0 +1,75 @@ +/* + * + * $FreeBSD$ + */ + +#include <machine/asm.h> + +ENTRY(host_read) + li %r0, 3 # SYS_read + sc + bso 1f + blr +1: + li %r3, 0 + blr + + +ENTRY(host_write) + li %r0, 4 # SYS_write + sc + blr + +ENTRY(host_seek) + mr %r4,%r5 + mr %r5,%r6 + mr %r6,%r7 + li %r0, 140 # SYS_llseek + sc + blr + +ENTRY(host_open) + li %r0, 5 # SYS_open + sc + bso 1f + blr +1: + li %r3, 0 + blr + +ENTRY(host_close) + li %r0, 6 # SYS_close + sc + blr + +ENTRY(host_mmap) + li %r0, 90 # SYS_mmap + sc + blr + +ENTRY(host_gettimeofday) + li %r0, 78 # SYS_gettimeofday + sc + blr + +ENTRY(host_select) + li %r0, 142 # SYS_select + sc + blr + +ENTRY(kexec_load) + lis %r6,21 # KEXEC_ARCH_PPC64 + li %r0,268 # __NR_kexec_load + sc + blr + +ENTRY(host_reboot) + li %r0,88 # SYS_reboot + sc + blr + +ENTRY(host_getdents) + li %r0,141 # SYS_getdents + sc + blr + diff --git a/stand/powerpc/kboot/host_syscall.h b/stand/powerpc/kboot/host_syscall.h new file mode 100644 index 000000000000..0d47bd58a44a --- /dev/null +++ b/stand/powerpc/kboot/host_syscall.h @@ -0,0 +1,51 @@ +/*- + * Copyright (C) 2014 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _HOST_SYSCALL_H +#define _HOST_SYSCALL_H + +#include <stand.h> + +ssize_t host_read(int fd, void *buf, size_t nbyte); +ssize_t host_write(int fd, const void *buf, size_t nbyte); +ssize_t host_seek(int fd, int64_t offset, int whence); +int host_open(char *path, int flags, int mode); +int host_close(int fd); +void *host_mmap(void *addr, size_t len, int prot, int flags, int fd, int); +#define host_getmem(size) host_mmap(0, size, 3 /* RW */, 0x22 /* ANON */, -1, 0); +struct host_timeval { + int tv_sec; + int tv_usec; +}; +int host_gettimeofday(struct host_timeval *a, void *b); +int host_select(int nfds, long *readfds, long *writefds, long *exceptfds, + struct host_timeval *timeout); +int kexec_load(vm_offset_t start, int nsegs, void *segs); +int host_reboot(int, int, int, void *); +int host_getdents(int fd, void *dirp, int count); + +#endif diff --git a/stand/powerpc/kboot/hostcons.c b/stand/powerpc/kboot/hostcons.c new file mode 100644 index 000000000000..31dceb019973 --- /dev/null +++ b/stand/powerpc/kboot/hostcons.c @@ -0,0 +1,97 @@ +/*- + * Copyright (C) 2014 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include "bootstrap.h" +#include "host_syscall.h" + +static void hostcons_probe(struct console *cp); +static int hostcons_init(int arg); +static void hostcons_putchar(int c); +static int hostcons_getchar(); +static int hostcons_poll(); + +struct console hostconsole = { + "host", + "Host Console", + 0, + hostcons_probe, + hostcons_init, + hostcons_putchar, + hostcons_getchar, + hostcons_poll, +}; + +static void +hostcons_probe(struct console *cp) +{ + + cp->c_flags |= C_PRESENTIN|C_PRESENTOUT; +} + +static int +hostcons_init(int arg) +{ + + /* XXX: set nonblocking */ + /* tcsetattr(~(ICANON | ECHO)) */ + + return (0); +} + +static void +hostcons_putchar(int c) +{ + uint8_t ch = c; + + host_write(1, &ch, 1); +} + +static int +hostcons_getchar() +{ + uint8_t ch; + int rv; + + rv = host_read(0, &ch, 1); + if (rv == 1) + return (ch); + return (-1); +} + +static int +hostcons_poll() +{ + struct host_timeval tv = {0,0}; + long fds = 1 << 0; + int ret; + + ret = host_select(32, &fds, NULL, NULL, &tv); + return (ret > 0); +} + diff --git a/stand/powerpc/kboot/hostdisk.c b/stand/powerpc/kboot/hostdisk.c new file mode 100644 index 000000000000..22f540674cc1 --- /dev/null +++ b/stand/powerpc/kboot/hostdisk.c @@ -0,0 +1,125 @@ +/*- + * Copyright (C) 2014 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <stdarg.h> +#include "bootstrap.h" +#include "host_syscall.h" + +static int hostdisk_init(void); +static int hostdisk_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); +static int hostdisk_open(struct open_file *f, ...); +static int hostdisk_close(struct open_file *f); +static int hostdisk_ioctl(struct open_file *f, u_long cmd, void *data); +static int hostdisk_print(int verbose); + +struct devsw hostdisk = { + "/dev", + DEVT_DISK, + hostdisk_init, + hostdisk_strategy, + hostdisk_open, + hostdisk_close, + hostdisk_ioctl, + hostdisk_print, +}; + +static int +hostdisk_init(void) +{ + + return (0); +} + +static int +hostdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, + char *buf, size_t *rsize) +{ + struct devdesc *desc = devdata; + daddr_t pos; + int n; + + pos = dblk * 512; + + if (host_seek(desc->d_unit, pos, 0) < 0) { + printf("Seek error\n"); + return (EIO); + } + n = host_read(desc->d_unit, buf, size); + + if (n < 0) + return (EIO); + + *rsize = n; + return (0); +} + +static int +hostdisk_open(struct open_file *f, ...) +{ + struct devdesc *desc; + va_list vl; + + va_start(vl, f); + desc = va_arg(vl, struct devdesc *); + va_end(vl); + + desc->d_unit = host_open(desc->d_opendata, O_RDONLY, 0); + + if (desc->d_unit <= 0) { + printf("hostdisk_open: couldn't open %s: %d\n", + desc->d_opendata, desc->d_unit); + return (ENOENT); + } + + return (0); +} + +static int +hostdisk_close(struct open_file *f) +{ + struct devdesc *desc = f->f_devdata; + + host_close(desc->d_unit); + return (0); +} + +static int +hostdisk_ioctl(struct open_file *f, u_long cmd, void *data) +{ + + return (EINVAL); +} + +static int +hostdisk_print(int verbose) +{ + return (0); +} + diff --git a/stand/powerpc/kboot/kbootfdt.c b/stand/powerpc/kboot/kbootfdt.c new file mode 100644 index 000000000000..5ab3c3da43c9 --- /dev/null +++ b/stand/powerpc/kboot/kbootfdt.c @@ -0,0 +1,184 @@ +/*- + * Copyright (C) 2014 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <fdt_platform.h> +#include <libfdt.h> +#include "bootstrap.h" +#include "host_syscall.h" + +static void +add_node_to_fdt(void *buffer, const char *path, int fdt_offset) +{ + int child_offset, fd, pfd, error, dentsize; + char subpath[512]; + void *propbuf; + ssize_t proplen; + + struct host_dent { + unsigned long d_fileno; + unsigned long d_off; + unsigned short d_reclen; + char d_name[]; + /* uint8_t d_type; */ + }; + char dents[2048]; + struct host_dent *dent; + int d_type; + + fd = host_open(path, O_RDONLY, 0); + while (1) { + dentsize = host_getdents(fd, dents, sizeof(dents)); + if (dentsize <= 0) + break; + for (dent = (struct host_dent *)dents; + (char *)dent < dents + dentsize; + dent = (struct host_dent *)((void *)dent + dent->d_reclen)) { + sprintf(subpath, "%s/%s", path, dent->d_name); + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + d_type = *((char *)(dent) + dent->d_reclen - 1); + if (d_type == 4 /* DT_DIR */) { + child_offset = fdt_add_subnode(buffer, fdt_offset, + dent->d_name); + if (child_offset < 0) { + printf("Error %d adding node %s/%s, skipping\n", + child_offset, path, dent->d_name); + continue; + } + + add_node_to_fdt(buffer, subpath, child_offset); + } else { + propbuf = malloc(1024); + proplen = 0; + pfd = host_open(subpath, O_RDONLY, 0); + if (pfd > 0) { + proplen = host_read(pfd, propbuf, 1024); + host_close(pfd); + } + error = fdt_setprop(buffer, fdt_offset, dent->d_name, + propbuf, proplen); + free(propbuf); + if (error) + printf("Error %d adding property %s to " + "node %d\n", error, dent->d_name, + fdt_offset); + } + } + } + + host_close(fd); +} + +/* Fix up wrong values added to the device tree by prom_init() in Linux */ + +static void +fdt_linux_fixups(void *fdtp) +{ + int offset, len; + const void *prop; + + /* + * Remove /memory/available properties, which reflect long-gone OF + * state + */ + + offset = fdt_path_offset(fdtp, "/memory@0"); + if (offset > 0) + fdt_delprop(fdtp, offset, "available"); + + /* + * Add reservations for OPAL and RTAS state if present + */ + + offset = fdt_path_offset(fdtp, "/ibm,opal"); + if (offset > 0) { + uint64_t *base, *size; + base = fdt_getprop(fdtp, offset, "opal-base-address", + &len); + size = fdt_getprop(fdtp, offset, "opal-runtime-size", + &len); + if (base != NULL && size != NULL) + fdt_add_mem_rsv(fdtp, fdt64_to_cpu(*base), + fdt64_to_cpu(*size)); + } + offset = fdt_path_offset(fdtp, "/rtas"); + if (offset > 0) { + uint32_t *base, *size; + base = fdt_getprop(fdtp, offset, "linux,rtas-base", &len); + size = fdt_getprop(fdtp, offset, "rtas-size", &len); + if (base != NULL && size != NULL) + fdt_add_mem_rsv(fdtp, fdt32_to_cpu(*base), + fdt32_to_cpu(*size)); + } + + /* + * Patch up /chosen nodes so that the stored handles mean something, + * where possible. + */ + offset = fdt_path_offset(fdtp, "/chosen"); + if (offset > 0) { + fdt_delprop(fdtp, offset, "cpu"); /* This node not meaningful */ + + offset = fdt_path_offset(fdtp, "/chosen"); + prop = fdt_getprop(fdtp, offset, "linux,stdout-package", &len); + if (prop != NULL) { + fdt_setprop(fdtp, offset, "stdout", prop, len); + offset = fdt_path_offset(fdtp, "/chosen"); + fdt_setprop(fdtp, offset, "stdin", prop, len); + } + } +} + +int +fdt_platform_load_dtb(void) +{ + void *buffer; + size_t buflen = 409600; + + buffer = malloc(buflen); + fdt_create_empty_tree(buffer, buflen); + add_node_to_fdt(buffer, "/proc/device-tree", + fdt_path_offset(buffer, "/")); + fdt_linux_fixups(buffer); + + fdt_pack(buffer); + + fdt_load_dtb_addr(buffer); + free(buffer); + + return (0); +} + +void +fdt_platform_fixups(void) +{ + +} + diff --git a/stand/powerpc/kboot/kerneltramp.S b/stand/powerpc/kboot/kerneltramp.S new file mode 100644 index 000000000000..a394c9554f30 --- /dev/null +++ b/stand/powerpc/kboot/kerneltramp.S @@ -0,0 +1,55 @@ +/* + * This is the analog to the kexec "purgatory" code + * + * The goal here is to call the actual kernel entry point with the arguments it + * expects when kexec calls into it with no arguments. The value of the kernel + * entry point and arguments r3-r7 are copied into the trampoline text (which + * can be executed from any address) at bytes 8-32. kexec begins execution + * of APs at 0x60 bytes past the entry point, executing in a copy relocated + * to the absolute address 0x60. Here we implement a loop waiting on the release + * of a lock by the kernel at 0x40. + * + * $FreeBSD$ + */ + +#include <machine/asm.h> + + .globl CNAME(kerneltramp),CNAME(szkerneltramp) +CNAME(kerneltramp): + mflr %r9 + bl 2f + .space 24 /* branch address, r3-r7 */ + +. = kerneltramp + 0x40 /* AP spinlock */ + .long 0 + +. = kerneltramp + 0x60 /* AP entry point */ + li %r3,0x40 +1: lwz %r1,0(%r3) + cmpwi %r1,0 + beq 1b + + /* Jump into CPU reset */ + li %r0,0x100 + icbi 0,%r0 + isync + sync + ba 0x100 + +2: /* Continuation of kerneltramp */ + mflr %r8 + mtlr %r9 + lwz %r3,0(%r8) + mtctr %r3 + lwz %r3,4(%r8) + lwz %r4,8(%r8) + lwz %r5,12(%r8) + lwz %r6,16(%r8) + lwz %r7,20(%r8) + bctr + +endkerneltramp: + + .data +CNAME(szkerneltramp): + .long endkerneltramp - CNAME(kerneltramp) diff --git a/stand/powerpc/kboot/ldscript.powerpc b/stand/powerpc/kboot/ldscript.powerpc new file mode 100644 index 000000000000..729113695105 --- /dev/null +++ b/stand/powerpc/kboot/ldscript.powerpc @@ -0,0 +1,111 @@ +/* $FreeBSD: user/nwhitehorn/kboot/powerpc/kboot/ldscript.powerpc 272888 2014-10-10 06:24:09Z bapt $ */ + +OUTPUT_FORMAT("elf32-powerpc-freebsd", "elf32-powerpc-freebsd", + "elf32-powerpc-freebsd") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +SEARCH_DIR(/usr/lib); +PROVIDE (__stack = 0); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x100000; + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.bss : { *(.rela.bss) } + .rela.plt : { *(.rela.plt) } + .rela.sbss : { *(.rela.sbss) } + .rela.sbss2 : { *(.rela.sbss2) } + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + .init : { *(.init) } =0 + .fini : { *(.fini) } =0 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .sbss2 : { *(.sbss2) } + /* Adjust the address for the data segment to the next page up. */ + . = ((. + 0x1000) & ~(0x1000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .got1 : { *(.got1) } + .dynamic : { *(.dynamic) } + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. + The current compiler no longer needs this, but keep it around for 2.7.2 */ + PROVIDE (_GOT2_START_ = .); + .got2 : { *(.got2) } + PROVIDE (__CTOR_LIST__ = .); + .ctors : { *(.ctors) } + PROVIDE (__CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + .dtors : { *(.dtors) } + PROVIDE (__DTOR_END__ = .); + PROVIDE (_FIXUP_START_ = .); + .fixup : { *(.fixup) } + PROVIDE (_FIXUP_END_ = .); + PROVIDE (_GOT2_END_ = .); + PROVIDE (_GOT_START_ = .); + .got : { *(.got) } + .got.plt : { *(.got.plt) } + PROVIDE (_GOT_END_ = .); + _edata = .; + PROVIDE (edata = .); + .sbss : + { + PROVIDE (__sbss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + PROVIDE (__sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + PROVIDE (__bss_start = .); + *(.dynbss) + *(.bss) + *(COMMON) + } + . = ALIGN(4096); + _end = . ; + PROVIDE (end = .); +} + diff --git a/stand/powerpc/kboot/main.c b/stand/powerpc/kboot/main.c new file mode 100644 index 000000000000..7a24c163d5c4 --- /dev/null +++ b/stand/powerpc/kboot/main.c @@ -0,0 +1,319 @@ +/*- + * Copyright (C) 2010-2014 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> +#include <fdt_platform.h> + +#define _KERNEL +#include <machine/cpufunc.h> +#include "bootstrap.h" +#include "host_syscall.h" + +struct arch_switch archsw; +extern void *_end; + +extern char bootprog_info[]; + +int kboot_getdev(void **vdev, const char *devspec, const char **path); +ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len); +ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len); +ssize_t kboot_readin(const int fd, vm_offset_t dest, const size_t len); +int kboot_autoload(void); +uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr); +int kboot_setcurrdev(struct env_var *ev, int flags, const void *value); + +extern int command_fdt_internal(int argc, char *argv[]); + +int +kboot_getdev(void **vdev, const char *devspec, const char **path) +{ + int i; + const char *devpath, *filepath; + struct devsw *dv; + struct devdesc *desc; + + if (strchr(devspec, ':') != NULL) { + devpath = devspec; + filepath = strchr(devspec, ':') + 1; + } else { + devpath = getenv("currdev"); + filepath = devspec; + } + + for (i = 0; (dv = devsw[i]) != NULL; i++) { + if (strncmp(dv->dv_name, devpath, strlen(dv->dv_name)) == 0) + goto found; + } + return (ENOENT); + +found: + if (path != NULL && filepath != NULL) + *path = filepath; + else if (path != NULL) + *path = strchr(devspec, ':') + 1; + + if (vdev != NULL) { + desc = malloc(sizeof(*desc)); + desc->d_dev = dv; + desc->d_unit = 0; + desc->d_opendata = strdup(devpath); + *vdev = desc; + } + + return (0); +} + +int +main(int argc, const char **argv) +{ + void *heapbase; + const size_t heapsize = 15*1024*1024; + const char *bootdev = argv[1]; + + /* + * Set the heap to one page after the end of the loader. + */ + heapbase = host_getmem(heapsize); + setheap(heapbase, heapbase + heapsize); + + /* + * Set up console. + */ + cons_probe(); + + printf("Boot device: %s\n", bootdev); + + archsw.arch_getdev = kboot_getdev; + archsw.arch_copyin = kboot_copyin; + archsw.arch_copyout = kboot_copyout; + archsw.arch_readin = kboot_readin; + archsw.arch_autoload = kboot_autoload; + archsw.arch_loadaddr = kboot_loadaddr; + + printf("\n%s", bootprog_info); + + setenv("currdev", bootdev, 1); + setenv("loaddev", bootdev, 1); + setenv("LINES", "24", 1); + + interact(NULL); /* doesn't return */ + + return (0); +} + +void +exit(int code) +{ + /* XXX: host_exit */ +} + +void +delay(int usecs) +{ + struct host_timeval tvi, tv; + uint64_t ti, t; + host_gettimeofday(&tvi, NULL); + ti = tvi.tv_sec*1000000 + tvi.tv_usec; + do { + host_gettimeofday(&tv, NULL); + t = tv.tv_sec*1000000 + tv.tv_usec; + } while (t < ti + usecs); +} + +time_t +getsecs(void) +{ + struct host_timeval tv; + host_gettimeofday(&tv, NULL); + return (tv.tv_sec); +} + +time_t +time(time_t *tloc) +{ + time_t rv; + + rv = getsecs(); + if (tloc != NULL) + *tloc = rv; + + return (rv); +} + +struct kexec_segment { + void *buf; + int bufsz; + void *mem; + int memsz; +}; + +struct kexec_segment loaded_segments[128]; +int nkexec_segments = 0; + +static ssize_t +get_phys_buffer(vm_offset_t dest, const size_t len, void **buf) +{ + int i = 0; + const size_t segsize = 2*1024*1024; + + for (i = 0; i < nkexec_segments; i++) { + if (dest >= (vm_offset_t)loaded_segments[i].mem && + dest < (vm_offset_t)loaded_segments[i].mem + + loaded_segments[i].memsz) + goto out; + } + + loaded_segments[nkexec_segments].buf = host_getmem(segsize); + loaded_segments[nkexec_segments].bufsz = segsize; + loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,segsize); + loaded_segments[nkexec_segments].memsz = segsize; + i = nkexec_segments; + nkexec_segments++; + +out: + *buf = loaded_segments[i].buf + (dest - + (vm_offset_t)loaded_segments[i].mem); + return (min(len,loaded_segments[i].bufsz - (dest - + (vm_offset_t)loaded_segments[i].mem))); +} + +ssize_t +kboot_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + ssize_t segsize, remainder; + void *destbuf; + + remainder = len; + do { + segsize = get_phys_buffer(dest, remainder, &destbuf); + bcopy(src, destbuf, segsize); + remainder -= segsize; + src += segsize; + dest += segsize; + } while (remainder > 0); + + return (len); +} + +ssize_t +kboot_copyout(vm_offset_t src, void *dest, const size_t len) +{ + ssize_t segsize, remainder; + void *srcbuf; + + remainder = len; + do { + segsize = get_phys_buffer(src, remainder, &srcbuf); + bcopy(srcbuf, dest, segsize); + remainder -= segsize; + src += segsize; + dest += segsize; + } while (remainder > 0); + + return (len); +} + +ssize_t +kboot_readin(const int fd, vm_offset_t dest, const size_t len) +{ + void *buf; + size_t resid, chunk, get; + ssize_t got; + vm_offset_t p; + + p = dest; + + chunk = min(PAGE_SIZE, len); + buf = malloc(chunk); + if (buf == NULL) { + printf("kboot_readin: buf malloc failed\n"); + return (0); + } + + for (resid = len; resid > 0; resid -= got, p += got) { + get = min(chunk, resid); + got = read(fd, buf, get); + if (got <= 0) { + if (got < 0) + printf("kboot_readin: read failed\n"); + break; + } + + kboot_copyin(buf, p, got); + } + + free (buf); + return (len - resid); +} + +int +kboot_autoload(void) +{ + + return (0); +} + +uint64_t +kboot_loadaddr(u_int type, void *data, uint64_t addr) +{ + /* + * Need to stay out of the way of Linux. /chosen/linux,kernel-end does + * a better job here, but use a fixed offset for now. + */ + + if (type == LOAD_ELF) + addr = roundup(addr, PAGE_SIZE); + else + addr += 64*1024*1024; /* Stay out of the way of Linux */ + + return (addr); +} + +void +_start(int argc, const char **argv, char **env) +{ + register volatile void **sp asm("r1"); + main((int)sp[0], (const char **)&sp[1]); +} + +/* + * Since proper fdt command handling function is defined in fdt_loader_cmd.c, + * and declaring it as extern is in contradiction with COMMAND_SET() macro + * (which uses static pointer), we're defining wrapper function, which + * calls the proper fdt handling routine. + */ +static int +command_fdt(int argc, char *argv[]) +{ + + return (command_fdt_internal(argc, argv)); +} + +COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); + diff --git a/stand/powerpc/kboot/metadata.c b/stand/powerpc/kboot/metadata.c new file mode 100644 index 000000000000..1e8c314c64e6 --- /dev/null +++ b/stand/powerpc/kboot/metadata.c @@ -0,0 +1,343 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> +#include <sys/boot.h> +#include <fdt_platform.h> + +#include <machine/metadata.h> + +#include "bootstrap.h" + +int +md_getboothowto(char *kargs) +{ + char *cp; + int howto; + int active; + int i; + + /* Parse kargs */ + howto = 0; + if (kargs != NULL) { + cp = kargs; + active = 0; + while (*cp != 0) { + if (!active && (*cp == '-')) { + active = 1; + } else if (active) + switch (*cp) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'C': + howto |= RB_CDROM; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'g': + howto |= RB_GDB; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'v': + howto |= RB_VERBOSE; + break; + default: + active = 0; + break; + } + cp++; + } + } + /* get equivalents from the environment */ + for (i = 0; howto_names[i].ev != NULL; i++) + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + if (!strcmp(getenv("console"), "comconsole")) + howto |= RB_SERIAL; + if (!strcmp(getenv("console"), "nullconsole")) + howto |= RB_MUTE; + return(howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as <name>=<value>, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +md_copyenv(vm_offset_t addr) +{ + struct env_var *ep; + + /* traverse the environment */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); + addr += strlen(ep->ev_name); + archsw.arch_copyin("=", addr, 1); + addr++; + if (ep->ev_value != NULL) { + archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); + addr += strlen(ep->ev_value); + } + archsw.arch_copyin("", addr, 1); + addr++; + } + archsw.arch_copyin("", addr, 1); + addr++; + return(addr); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ + +static int align; + +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + archsw.arch_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c) \ + if (c) \ + archsw.arch_copyin(s, a, strlen(s) + 1);\ + a += roundup(strlen(s) + 1, align); \ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + archsw.arch_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), align); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c);\ + COPY32(mm->md_size, a, c); \ + if (c) \ + archsw.arch_copyin(mm->md_data, a, mm->md_size);\ + a += roundup(mm->md_size, align); \ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +vm_offset_t +md_copymodules(vm_offset_t addr, int kern64) +{ + struct preloaded_file *fp; + struct file_metadata *md; + uint64_t scratch64; + int c; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + if (kern64) { + scratch64 = fp->f_addr; + MOD_ADDR(addr, scratch64, c); + scratch64 = fp->f_size; + MOD_SIZE(addr, scratch64, c); + } else { + MOD_ADDR(addr, fp->f_addr, c); + MOD_SIZE(addr, fp->f_size, c); + } + for (md = fp->f_metadata; md != NULL; md = md->md_next) { + if (!(md->md_type & MODINFOMD_NOCOPY)) { + MOD_METADATA(addr, md, c); + } + } + } + MOD_END(addr, c); + return(addr); +} + +/* + * Load the information expected by a powerpc kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) +{ + struct preloaded_file *kfp; + struct preloaded_file *xp; + struct file_metadata *md; + vm_offset_t kernend; + vm_offset_t addr; + vm_offset_t envp; + vm_offset_t fdtp; + vm_offset_t size; + uint64_t scratch64; + char *rootdevname; + int howto; + + align = kern64 ? 8 : 4; + howto = md_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + if (rootdevname == NULL) + rootdevname = getenv("currdev"); + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(rootdevname); + + /* find the last module in the chain */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* copy our environment */ + envp = addr; + addr = md_copyenv(addr); + + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* Copy out FDT */ + size = fdt_copy(addr); + *dtb = fdtp = addr; + addr = roundup(addr + size, PAGE_SIZE); + + kernend = 0; + kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + if (kern64) { + scratch64 = envp; + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); + scratch64 = fdtp; + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64); + scratch64 = kernend; + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64); + } else { + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + } + + *modulep = addr; + size = md_copymodules(0, kern64); + kernend = roundup(addr + size, PAGE_SIZE); + + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + if (kern64) { + scratch64 = kernend; + bcopy(&scratch64, md->md_data, sizeof scratch64); + } else { + bcopy(&kernend, md->md_data, sizeof kernend); + } + + (void)md_copymodules(addr, kern64); + + return(0); +} + +int +md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtb) +{ + return (md_load_dual(args, modulep, dtb, 0)); +} + +int +md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb) +{ + return (md_load_dual(args, modulep, dtb, 1)); +} + diff --git a/stand/powerpc/kboot/ppc64_elf_freebsd.c b/stand/powerpc/kboot/ppc64_elf_freebsd.c new file mode 100644 index 000000000000..22fa7b576775 --- /dev/null +++ b/stand/powerpc/kboot/ppc64_elf_freebsd.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2001 Benno Rice <benno@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 + +#include <sys/param.h> +#include <sys/linker.h> + +#include <machine/metadata.h> +#include <machine/elf.h> + +#include <stand.h> + +#include "bootstrap.h" +#include "host_syscall.h" + +extern char end[]; +extern void *kerneltramp; +extern size_t szkerneltramp; +extern int nkexec_segments; +extern void * loaded_segments; + +int +ppc64_elf_loadfile(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + int r; + + r = __elfN(loadfile)(filename, dest, result); + if (r != 0) + return (r); + + return (0); +} + +int +ppc64_elf_exec(struct preloaded_file *fp) +{ + struct file_metadata *fmp; + vm_offset_t mdp, dtb; + Elf_Ehdr *e; + int error; + uint32_t *trampoline; + uint64_t entry; + vm_offset_t trampolinebase; + + if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) { + return(EFTYPE); + } + e = (Elf_Ehdr *)&fmp->md_data; + + /* Figure out where to put it */ + trampolinebase = archsw.arch_loadaddr(LOAD_RAW, NULL, 0); + + /* Set up loader trampoline */ + trampoline = malloc(szkerneltramp); + memcpy(trampoline, &kerneltramp, szkerneltramp); + /* Parse function descriptor for ELFv1 kernels */ + if ((e->e_flags & 3) == 2) + entry = e->e_entry; + else + archsw.arch_copyout(e->e_entry + elf64_relocation_offset, + &entry, 8); + trampoline[2] = entry + elf64_relocation_offset; + trampoline[4] = 0; /* Phys. mem offset */ + trampoline[5] = 0; /* OF entry point */ + + if ((error = md_load64(fp->f_args, &mdp, &dtb)) != 0) + return (error); + + trampoline[3] = dtb; + trampoline[6] = mdp; + trampoline[7] = sizeof(mdp); + printf("Kernel entry at %#jx (%#x) ...\n", e->e_entry, trampoline[2]); + printf("DTB at %#x, mdp at %#x\n", dtb, mdp); + + dev_cleanup(); + + archsw.arch_copyin(trampoline, trampolinebase, szkerneltramp); + free(trampoline); + + error = kexec_load(trampolinebase, nkexec_segments, &loaded_segments); + if (error != 0) + panic("kexec_load returned error: %d", error); + error = host_reboot(0xfee1dead, 672274793, + 0x45584543 /* LINUX_REBOOT_CMD_KEXEC */, NULL); + if (error != 0) + panic("reboot returned error: %d", error); + while (1) {} + + panic("exec returned"); +} + +struct file_format ppc_elf64 = +{ + ppc64_elf_loadfile, + ppc64_elf_exec +}; diff --git a/stand/powerpc/kboot/version b/stand/powerpc/kboot/version new file mode 100644 index 000000000000..b24d6ea8e47a --- /dev/null +++ b/stand/powerpc/kboot/version @@ -0,0 +1,6 @@ +$FreeBSD: user/nwhitehorn/kboot/powerpc/kboot/version 224106 2011-07-16 19:01:09Z nwhitehorn $ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +0.1: Initial kboot/PowerPC version. diff --git a/stand/powerpc/ofw/Makefile b/stand/powerpc/ofw/Makefile new file mode 100644 index 000000000000..1853b2596fce --- /dev/null +++ b/stand/powerpc/ofw/Makefile @@ -0,0 +1,55 @@ +# $FreeBSD$ + +LOADER_CD9660_SUPPORT?= yes +LOADER_EXT2FS_SUPPORT?= no +LOADER_MSDOS_SUPPORT?= no +LOADER_UFS_SUPPORT?= yes +LOADER_NET_SUPPORT?= yes +LOADER_NFS_SUPPORT?= yes +LOADER_TFTP_SUPPORT?= no +LOADER_GZIP_SUPPORT?= yes +LOADER_BZIP2_SUPPORT?= no + +.include <bsd.init.mk> +MK_SSP= no +MAN= + +PROG= loader +NEWVERSWHAT= "Open Firmware loader" ${MACHINE_ARCH} +INSTALLFLAGS= -b + +# Architecture-specific loader code +SRCS= conf.c metadata.c vers.c start.c +SRCS+= ucmpdi2.c + +.include "${BOOTSRC}/fdt.mk" +.if ${MK_FDT} == "yes" +SRCS+= ofwfdt.c +.endif + +HELP_FILES+= ${FDTSRC}/help.fdt + +# Always add MI sources +.include "${BOOTSRC}/loader.mk" + +.PATH: ${SYSDIR}/libkern + +CFLAGS+= -ffreestanding -msoft-float +# load address. set in linker script +RELOC?= 0x1C00000 +CFLAGS+= -DRELOC=${RELOC} + +LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.powerpc + +# Pull in common loader code +.PATH: ${BOOTSRC}/ofw/common +.include "${BOOTSRC}/ofw/common/Makefile.inc" + +# Open Firmware standalone support library +LIBOFW= ${BOOTOBJ}/ofw/libofw/libofw.a +CFLAGS+= -I${BOOTSRC}/ofw/libofw + +DPADD= ${LIBFICL} ${LIBOFW} ${LIBFDT} ${LIBSA} +LDADD= ${LIBFICL} ${LIBOFW} ${LIBFDT} ${LIBSA} + +.include <bsd.prog.mk> diff --git a/stand/powerpc/ofw/conf.c b/stand/powerpc/ofw/conf.c new file mode 100644 index 000000000000..7cad372cef04 --- /dev/null +++ b/stand/powerpc/ofw/conf.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "bootstrap.h" +#include "libofw.h" +#include "openfirm.h" + +#if defined(LOADER_NET_SUPPORT) +#include "dev_net.h" +#endif + +/* Make sure we have an explicit reference to exit so libsa's panic pulls in the MD exit */ +void (*exitfn)(int) = exit; + +/* + * We could use linker sets for some or all of these, but + * then we would have to control what ended up linked into + * the bootstrap. So it's easier to conditionalise things + * here. + * + * XXX rename these arrays to be consistent and less namespace-hostile + */ + +/* Exported for libstand */ +struct devsw *devsw[] = { +#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT) + &ofwdisk, +#endif +#if defined(LOADER_NET_SUPPORT) + &netdev, +#endif + NULL +}; + +struct fs_ops *file_system[] = { +#if defined(LOADER_UFS_SUPPORT) + &ufs_fsops, +#endif +#if defined(LOADER_CD9660_SUPPORT) + &cd9660_fsops, +#endif +#if defined(LOADER_EXT2FS_SUPPORT) + &ext2fs_fsops, +#endif +#if defined(LOADER_NFS_SUPPORT) + &nfs_fsops, +#endif +#if defined(LOADER_TFTP_SUPPORT) + &tftp_fsops, +#endif +#if defined(LOADER_GZIP_SUPPORT) + &gzipfs_fsops, +#endif +#if defined(LOADER_BZIP2_SUPPORT) + &bzipfs_fsops, +#endif + NULL +}; + +struct netif_driver *netif_drivers[] = { +#if defined(LOADER_NET_SUPPORT) + &ofwnet, +#endif + NULL, +}; + +/* Exported for PowerPC only */ +/* + * Sort formats so that those that can detect based on arguments + * rather than reading the file go first. + */ + +struct file_format *file_formats[] = { + &ofw_elf, + &ofw_elf64, + NULL +}; + +/* + * Consoles + * + * We don't prototype these in libofw.h because they require + * data structures from bootstrap.h as well. + */ +extern struct console ofwconsole; + +struct console *consoles[] = { + &ofwconsole, + NULL +}; + +/* + * reloc - our load address + */ +vm_offset_t reloc = RELOC; diff --git a/stand/powerpc/ofw/ldscript.powerpc b/stand/powerpc/ofw/ldscript.powerpc new file mode 100644 index 000000000000..3a2765047dbb --- /dev/null +++ b/stand/powerpc/ofw/ldscript.powerpc @@ -0,0 +1,138 @@ +/* $FreeBSD$ */ + +OUTPUT_FORMAT("elf32-powerpc-freebsd", "elf32-powerpc-freebsd", + "elf32-powerpc-freebsd") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +SEARCH_DIR(/usr/lib); +PROVIDE (__stack = 0); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x01c00000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.bss : { *(.rela.bss) } + .rela.plt : { *(.rela.plt) } + .rela.sdata : { *(.rela.sdata) } + .rela.sbss : { *(.rela.sbss) } + .rela.sdata2 : { *(.rela.sdata2) } + .rela.sbss2 : { *(.rela.sbss2) } + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + .init : { *(.init) } =0 + .fini : { *(.fini) } =0 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2) } + .sbss2 : { *(.sbss2) } + /* Adjust the address for the data segment to the next page up. */ + . = ((. + 0x1000) & ~(0x1000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .got1 : { *(.got1) } + .dynamic : { *(.dynamic) } + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. + The current compiler no longer needs this, but keep it around for 2.7.2 */ + PROVIDE (_GOT2_START_ = .); + .got2 : { *(.got2) } + PROVIDE (__CTOR_LIST__ = .); + .ctors : { *(.ctors) } + PROVIDE (__CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + .dtors : { *(.dtors) } + PROVIDE (__DTOR_END__ = .); + PROVIDE (_FIXUP_START_ = .); + .fixup : { *(.fixup) } + PROVIDE (_FIXUP_END_ = .); + PROVIDE (_GOT2_END_ = .); + PROVIDE (_GOT_START_ = .); + .got : { *(.got) } + .got.plt : { *(.got.plt) } + PROVIDE (_GOT_END_ = .); + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + .sbss : + { + PROVIDE (__sbss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + PROVIDE (__sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + PROVIDE (__bss_start = .); + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} + diff --git a/stand/powerpc/ofw/metadata.c b/stand/powerpc/ofw/metadata.c new file mode 100644 index 000000000000..25d51f8251ce --- /dev/null +++ b/stand/powerpc/ofw/metadata.c @@ -0,0 +1,349 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> +#include <sys/boot.h> +#include <fdt_platform.h> + +#include <machine/metadata.h> + +#include "bootstrap.h" + +int +md_getboothowto(char *kargs) +{ + char *cp; + int howto; + int active; + int i; + + /* Parse kargs */ + howto = 0; + if (kargs != NULL) { + cp = kargs; + active = 0; + while (*cp != 0) { + if (!active && (*cp == '-')) { + active = 1; + } else if (active) + switch (*cp) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'C': + howto |= RB_CDROM; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'g': + howto |= RB_GDB; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'v': + howto |= RB_VERBOSE; + break; + default: + active = 0; + break; + } + cp++; + } + } + /* get equivalents from the environment */ + for (i = 0; howto_names[i].ev != NULL; i++) + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + if (!strcmp(getenv("console"), "comconsole")) + howto |= RB_SERIAL; + if (!strcmp(getenv("console"), "nullconsole")) + howto |= RB_MUTE; + return(howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as <name>=<value>, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +md_copyenv(vm_offset_t addr) +{ + struct env_var *ep; + + /* traverse the environment */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); + addr += strlen(ep->ev_name); + archsw.arch_copyin("=", addr, 1); + addr++; + if (ep->ev_value != NULL) { + archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); + addr += strlen(ep->ev_value); + } + archsw.arch_copyin("", addr, 1); + addr++; + } + archsw.arch_copyin("", addr, 1); + addr++; + return(addr); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ + +static int align; + +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + archsw.arch_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c) \ + if (c) \ + archsw.arch_copyin(s, a, strlen(s) + 1);\ + a += roundup(strlen(s) + 1, align); \ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + archsw.arch_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), align); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c);\ + COPY32(mm->md_size, a, c); \ + if (c) \ + archsw.arch_copyin(mm->md_data, a, mm->md_size);\ + a += roundup(mm->md_size, align); \ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +vm_offset_t +md_copymodules(vm_offset_t addr, int kern64) +{ + struct preloaded_file *fp; + struct file_metadata *md; + uint64_t scratch64; + int c; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + if (kern64) { + scratch64 = fp->f_addr; + MOD_ADDR(addr, scratch64, c); + scratch64 = fp->f_size; + MOD_SIZE(addr, scratch64, c); + } else { + MOD_ADDR(addr, fp->f_addr, c); + MOD_SIZE(addr, fp->f_size, c); + } + for (md = fp->f_metadata; md != NULL; md = md->md_next) { + if (!(md->md_type & MODINFOMD_NOCOPY)) { + MOD_METADATA(addr, md, c); + } + } + } + MOD_END(addr, c); + return(addr); +} + +/* + * Load the information expected by a powerpc kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) +{ + struct preloaded_file *kfp; + struct preloaded_file *xp; + struct file_metadata *md; + vm_offset_t kernend; + vm_offset_t addr; + vm_offset_t envp; + vm_offset_t fdtp; + vm_offset_t size; + uint64_t scratch64; + char *rootdevname; + int howto; + + align = kern64 ? 8 : 4; + howto = md_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + if (rootdevname == NULL) + rootdevname = getenv("currdev"); + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(rootdevname); + + /* find the last module in the chain */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* copy our environment */ + envp = addr; + addr = md_copyenv(addr); + + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* Copy out FDT */ + *dtb = fdtp = 0; + if (getenv("usefdt") != NULL) { + size = fdt_copy(addr); + *dtb = fdtp = addr; + addr = roundup(addr + size, PAGE_SIZE); + } + + kernend = 0; + kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + if (kern64) { + scratch64 = envp; + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); + if (fdtp != 0) { + scratch64 = fdtp; + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64); + } + scratch64 = kernend; + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64); + } else { + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + if (fdtp != 0) + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + } + + *modulep = addr; + size = md_copymodules(0, kern64); + kernend = roundup(addr + size, PAGE_SIZE); + + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + if (kern64) { + scratch64 = kernend; + bcopy(&scratch64, md->md_data, sizeof scratch64); + } else { + bcopy(&kernend, md->md_data, sizeof kernend); + } + + (void)md_copymodules(addr, kern64); + + return(0); +} + +int +md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtb) +{ + return (md_load_dual(args, modulep, dtb, 0)); +} + +int +md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb) +{ + return (md_load_dual(args, modulep, dtb, 1)); +} + diff --git a/stand/powerpc/ofw/ofwfdt.c b/stand/powerpc/ofw/ofwfdt.c new file mode 100644 index 000000000000..493bae7576fb --- /dev/null +++ b/stand/powerpc/ofw/ofwfdt.c @@ -0,0 +1,214 @@ +/*- + * Copyright (C) 2014-2015 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> +#include <fdt_platform.h> +#include <openfirm.h> +#include <libfdt.h> +#include "bootstrap.h" + +extern int command_fdt_internal(int argc, char *argv[]); + +static int +OF_hasprop(phandle_t node, const char *prop) +{ + return (OF_getproplen(node, (char *)prop) > 0); +} + +static void +add_node_to_fdt(void *buffer, phandle_t node, int fdt_offset) +{ + int i, child_offset, error; + char name[255], *lastprop, *subname; + void *propbuf; + ssize_t proplen; + + lastprop = NULL; + while (OF_nextprop(node, lastprop, name) > 0) { + proplen = OF_getproplen(node, name); + + /* Detect and correct for errors and strangeness */ + if (proplen < 0) + proplen = 0; + if (proplen > 1024) + proplen = 1024; + + propbuf = malloc(proplen); + if (propbuf == NULL) { + printf("Cannot allocate memory for prop %s\n", name); + return; + } + OF_getprop(node, name, propbuf, proplen); + error = fdt_setprop(buffer, fdt_offset, name, propbuf, proplen); + free(propbuf); + lastprop = name; + if (error) + printf("Error %d adding property %s to " + "node %d\n", error, name, fdt_offset); + } + + if (!OF_hasprop(node, "phandle") && !OF_hasprop(node, "linux,phandle") + && !OF_hasprop(node, "ibm,phandle")) + fdt_setprop(buffer, fdt_offset, "phandle", &node, sizeof(node)); + + for (node = OF_child(node); node > 0; node = OF_peer(node)) { + OF_package_to_path(node, name, sizeof(name)); + subname = strrchr(name, '/'); + subname++; + child_offset = fdt_add_subnode(buffer, fdt_offset, subname); + if (child_offset < 0) { + printf("Error %d adding node %s (%s), skipping\n", + child_offset, name, subname); + continue; + } + + add_node_to_fdt(buffer, node, child_offset); + } +} + +static void +ofwfdt_fixups(void *fdtp) +{ + int offset, len, i; + phandle_t node; + ihandle_t rtas; + const void *prop; + + /* + * Instantiate and add reservations for RTAS state if present + */ + + offset = fdt_path_offset(fdtp, "/rtas"); + if (offset > 0) { + uint32_t base; + void *rtasmem; + char path[255]; + + node = OF_finddevice("/rtas"); + OF_package_to_path(node, path, sizeof(path)); + OF_getprop(node, "rtas-size", &len, sizeof(len)); + + /* Allocate memory */ + rtasmem = OF_claim(0, len, 4096); + + /* Instantiate RTAS */ + rtas = OF_open(path); + base = 0; + OF_call_method("instantiate-rtas", rtas, 1, 1, (cell_t)rtas, + &base); + + /* Store info to FDT using Linux convention */ + base = cpu_to_fdt32(base); + fdt_setprop(fdtp, offset, "linux,rtas-entry", &base, + sizeof(base)); + base = cpu_to_fdt32((uint32_t)rtasmem); + offset = fdt_path_offset(fdtp, "/rtas"); + fdt_setprop(fdtp, offset, "linux,rtas-base", &base, + sizeof(base)); + + /* Mark RTAS private data area reserved */ + fdt_add_mem_rsv(fdtp, base, len); + } else { + /* + * Remove /memory/available properties, which reflect long-gone + * OF state. Note that this doesn't work if we need RTAS still, + * since that's part of the firmware. + */ + offset = fdt_path_offset(fdtp, "/memory@0"); + if (offset > 0) + fdt_delprop(fdtp, offset, "available"); + } + + + /* + * Convert stored ihandles under /chosen to xref phandles + */ + offset = fdt_path_offset(fdtp, "/chosen"); + if (offset > 0) { + const char *chosenprops[] = {"stdout", "stdin", "mmu", "cpu", + NULL}; + const uint32_t *ihand; + for (i = 0; chosenprops[i] != NULL; i++) { + ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len); + if (ihand != NULL && len == sizeof(*ihand)) { + node = OF_instance_to_package( + fdt32_to_cpu(*ihand)); + if (OF_hasprop(node, "phandle")) + OF_getprop(node, "phandle", &node, + sizeof(node)); + else if (OF_hasprop(node, "linux,phandle")) + OF_getprop(node, "linux,phandle", &node, + sizeof(node)); + else if (OF_hasprop(node, "ibm,phandle")) + OF_getprop(node, "ibm,phandle", &node, + sizeof(node)); + node = cpu_to_fdt32(node); + fdt_setprop(fdtp, offset, chosenprops[i], &node, + sizeof(node)); + } + + /* Refind node in case it moved */ + offset = fdt_path_offset(fdtp, "/chosen"); + } + } +} + +int +fdt_platform_load_dtb(void) +{ + void *buffer; + size_t buflen = 409600; + + buffer = malloc(buflen); + fdt_create_empty_tree(buffer, buflen); + add_node_to_fdt(buffer, OF_peer(0), fdt_path_offset(buffer, "/")); + ofwfdt_fixups(buffer); + fdt_pack(buffer); + + fdt_load_dtb_addr(buffer); + free(buffer); + + return (0); +} + +void +fdt_platform_fixups(void) +{ + +} + +static int +command_fdt(int argc, char *argv[]) +{ + + return (command_fdt_internal(argc, argv)); +} + +COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); + diff --git a/stand/powerpc/ofw/start.c b/stand/powerpc/ofw/start.c new file mode 100644 index 000000000000..911a2ec2af77 --- /dev/null +++ b/stand/powerpc/ofw/start.c @@ -0,0 +1,74 @@ +/* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ +/*- + * Copyright (C) 1995, 1996 Wolfgang Solfrank. + * Copyright (C) 1995, 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "libofw.h" + +void startup(void *, int, int (*)(void *), char *, int); + +__asm(" \n\ + .data \n\ + .align 4 \n\ +stack: \n\ + .space 16388 \n\ + \n\ + .text \n\ + .globl _start \n\ +_start: \n\ + lis %r1,stack@ha \n\ + addi %r1,%r1,stack@l \n\ + addi %r1,%r1,8192 \n\ + \n\ + /* Clear the .bss!!! */ \n\ + li %r0,0 \n\ + lis %r8,_edata@ha \n\ + addi %r8,%r8,_edata@l\n\ + lis %r9,_end@ha \n\ + addi %r9,%r9,_end@l \n\ + \n\ +1: cmpw 0,%r8,%r9 \n\ + bge 2f \n\ + stw %r0,0(%r8) \n\ + addi %r8,%r8,4 \n\ + b 1b \n\ + \n\ +2: b startup \n\ +"); + +void +startup(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl) +{ + main(openfirm); +} diff --git a/stand/powerpc/ofw/version b/stand/powerpc/ofw/version new file mode 100644 index 000000000000..cb0f6938f966 --- /dev/null +++ b/stand/powerpc/ofw/version @@ -0,0 +1,6 @@ +$FreeBSD$ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +0.1: Initial OFW/PowerPC version. diff --git a/stand/powerpc/ps3/Makefile b/stand/powerpc/ps3/Makefile new file mode 100644 index 000000000000..07ad135d9796 --- /dev/null +++ b/stand/powerpc/ps3/Makefile @@ -0,0 +1,48 @@ +# $FreeBSD$ + +LOADER_UFS_SUPPORT?= yes +LOADER_CD9660_SUPPORT?= yes +LOADER_EXT2FS_SUPPORT?= yes +LOADER_NET_SUPPORT?= yes +LOADER_NFS_SUPPORT?= yes +LOADER_TFTP_SUPPORT?= no +LOADER_GZIP_SUPPORT?= yes +LOADER_BZIP2_SUPPORT?= no + +.include <bsd.init.mk> +MK_SSP= no +MAN= + +PROG= loader.ps3 +NEWVERSWHAT= "Playstation 3 loader" ${MACHINE_ARCH} +INSTALLFLAGS= -b + +# Architecture-specific loader code +SRCS= start.S conf.c metadata.c vers.c main.c devicename.c ppc64_elf_freebsd.c +SRCS+= lv1call.S ps3cons.c font.h ps3mmu.c ps3net.c ps3repo.c \ + ps3stor.c ps3disk.c ps3cdrom.c +SRCS+= ucmpdi2.c + +CFLAGS+= -mcpu=powerpc64 + +# Always add MI sources +HELP_FILES= # Disable +.include "${BOOTSRC}/loader.mk" +.PATH: ${SYSDIR}/libkern + +CFLAGS+= -Wall -ffreestanding -msoft-float -DAIM +# load address. set in linker script +RELOC?= 0x0 +CFLAGS+= -DRELOC=${RELOC} + +LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.powerpc + +DPADD= ${LIBFICL} ${LIBOFW} ${LIBSA} +LDADD= ${LIBFICL} ${LIBOFW} ${LIBSA} + +SC_DFLT_FONT=cp437 + +font.h: + uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h + +.include <bsd.prog.mk> diff --git a/stand/powerpc/ps3/conf.c b/stand/powerpc/ps3/conf.c new file mode 100644 index 000000000000..3a5ae4c41f02 --- /dev/null +++ b/stand/powerpc/ps3/conf.c @@ -0,0 +1,123 @@ +/*- + * Copyright (C) 1999 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "bootstrap.h" + +#if defined(LOADER_NET_SUPPORT) +#include "dev_net.h" +#endif + +extern struct devsw ps3disk; +extern struct devsw ps3cdrom; + +/* + * We could use linker sets for some or all of these, but + * then we would have to control what ended up linked into + * the bootstrap. So it's easier to conditionalise things + * here. + * + * XXX rename these arrays to be consistent and less namespace-hostile + */ + +/* Exported for libstand */ +struct devsw *devsw[] = { +#if defined(LOADER_CD9660_SUPPORT) + &ps3cdrom, +#endif +#if defined(LOADER_DISK_SUPPORT) + &ps3disk, +#endif +#if defined(LOADER_NET_SUPPORT) + &netdev, +#endif + NULL +}; + +struct fs_ops *file_system[] = { +#if defined(LOADER_UFS_SUPPORT) + &ufs_fsops, +#endif +#if defined(LOADER_CD9660_SUPPORT) + &cd9660_fsops, +#endif +#if defined(LOADER_EXT2FS_SUPPORT) + &ext2fs_fsops, +#endif +#if defined(LOADER_NFS_SUPPORT) + &nfs_fsops, +#endif +#if defined(LOADER_TFTP_SUPPORT) + &tftp_fsops, +#endif +#if defined(LOADER_GZIP_SUPPORT) + &gzipfs_fsops, +#endif +#if defined(LOADER_BZIP2_SUPPORT) + &bzipfs_fsops, +#endif + NULL +}; + +extern struct netif_driver ps3net; + +struct netif_driver *netif_drivers[] = { +#if defined(LOADER_NET_SUPPORT) + &ps3net, +#endif + NULL, +}; + +/* Exported for PowerPC only */ +/* + * Sort formats so that those that can detect based on arguments + * rather than reading the file go first. + */ + +extern struct file_format ppc_elf64; + +struct file_format *file_formats[] = { + &ppc_elf64, + NULL +}; + +/* + * Consoles + */ +extern struct console ps3console; + +struct console *consoles[] = { + &ps3console, + NULL +}; + +/* + * reloc - our load address + */ +vm_offset_t reloc = RELOC; diff --git a/stand/powerpc/ps3/devicename.c b/stand/powerpc/ps3/devicename.c new file mode 100644 index 000000000000..041f853986d5 --- /dev/null +++ b/stand/powerpc/ps3/devicename.c @@ -0,0 +1,238 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/disklabel.h> + +#include <stand.h> +#include <string.h> + +#include "bootstrap.h" +#include "ps3.h" +#include "ps3devdesc.h" + +static int ps3_parsedev(struct ps3_devdesc **dev, const char *devspec, + const char **path); + +/* + * Point (dev) at an allocated device specifier for the device matching the + * path in (devspec). If it contains an explicit device specification, + * use that. If not, use the default device. + */ +int +ps3_getdev(void **vdev, const char *devspec, const char **path) +{ + struct ps3_devdesc **dev = (struct ps3_devdesc **)vdev; + int rv = 0; + + /* + * If it looks like this is just a path and no + * device, go with the current device. + */ + if ((devspec == NULL) || (devspec[0] == '/') || + (strchr(devspec, ':') == NULL)) { + rv = ps3_parsedev(dev, getenv("currdev"), NULL); + + if (rv == 0 && path != NULL) + *path = devspec; + return(rv); + } + + /* + * Try to parse the device name off the beginning of the devspec. + */ + return (ps3_parsedev(dev, devspec, path)); +} + +/* + * Point (dev) at an allocated device specifier matching the string version + * at the beginning of (devspec). Return a pointer to the remaining + * text in (path). + * + * In all cases, the beginning of (devspec) is compared to the names + * of known devices in the device switch, and then any following text + * is parsed according to the rules applied to the device type. + * + * For disk-type devices, the syntax is: + * + * disk<unit>[<partition>]: + * + */ +static int +ps3_parsedev(struct ps3_devdesc **dev, const char *devspec, const char **path) +{ + struct ps3_devdesc *idev; + struct devsw *dv; + char *cp; + const char *np; + int i, unit, pnum, ptype, err; + + /* minimum length check */ + if (strlen(devspec) < 2) + return(EINVAL); + + /* look for a device that matches */ + for (i = 0, dv = NULL; devsw[i] != NULL; i++) { + if (!strncmp(devspec, devsw[i]->dv_name, + strlen(devsw[i]->dv_name))) { + dv = devsw[i]; + break; + } + } + if (dv == NULL) + return(ENOENT); + idev = malloc(sizeof(struct ps3_devdesc)); + err = 0; + np = (devspec + strlen(dv->dv_name)); + + switch(dv->dv_type) { + case DEVT_NONE: + break; + + case DEVT_DISK: + unit = -1; + pnum = -1; + ptype = -1; + if (*np && (*np != ':')) { + /* next comes the unit number */ + unit = strtol(np, &cp, 10); + if (cp == np) { + err = EUNIT; + goto fail; + } + if (*cp && (*cp != ':')) { + /* get partition */ + if (*cp == 'p' && *(cp + 1) && + *(cp + 1) != ':') { + pnum = strtol(cp + 1, &cp, 10); + ptype = PTYPE_GPT; + } else { + pnum = *cp - 'a'; + ptype = PTYPE_BSDLABEL; + if ((pnum < 0) || + (pnum >= MAXPARTITIONS)) { + err = EPART; + goto fail; + } + cp++; + } + } + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + + idev->d_unit = unit; + idev->d_disk.pnum = pnum; + idev->d_disk.ptype = ptype; + idev->d_disk.data = NULL; + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; + + case DEVT_NET: + case DEVT_CD: + /* + * PS3 only has one network interface (well, two, but + * netbooting over wireless is not something I'm going + * to worry about. + */ + + idev->d_unit = 0; + break; + + default: + err = EINVAL; + goto fail; + } + idev->d_dev = dv; + idev->d_type = dv->dv_type; + if (dev == NULL) { + free(idev); + } else { + *dev = idev; + } + return (0); + +fail: + free(idev); + return (err); +} + + +char * +ps3_fmtdev(void *vdev) +{ + struct ps3_devdesc *dev = (struct ps3_devdesc *)vdev; + char *cp; + static char buf[128]; + + switch(dev->d_type) { + case DEVT_NONE: + strcpy(buf, "(no device)"); + break; + + case DEVT_DISK: + cp = buf; + cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit); + if (dev->d_kind.disk.pnum >= 0) { + if (dev->d_kind.disk.ptype == PTYPE_BSDLABEL) + cp += sprintf(cp, "%c", + dev->d_kind.disk.pnum + 'a'); + else if (dev->d_kind.disk.ptype == PTYPE_GPT) + cp += sprintf(cp, "p%i", + dev->d_kind.disk.pnum); + } + + strcat(cp, ":"); + break; + + case DEVT_NET: + case DEVT_CD: + sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); + break; + } + return(buf); +} + +/* + * Set currdev to suit the value being supplied in (value). + */ +int +ps3_setcurrdev(struct env_var *ev, int flags, const void *value) +{ + struct ps3_devdesc *ncurr; + int rv; + + if ((rv = ps3_parsedev(&ncurr, value, NULL)) != 0) + return (rv); + free(ncurr); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return (0); +} diff --git a/stand/powerpc/ps3/ldscript.powerpc b/stand/powerpc/ps3/ldscript.powerpc new file mode 100644 index 000000000000..12f3e751fb52 --- /dev/null +++ b/stand/powerpc/ps3/ldscript.powerpc @@ -0,0 +1,111 @@ +/* $FreeBSD$ */ + +OUTPUT_FORMAT("elf32-powerpc-freebsd", "elf32-powerpc-freebsd", + "elf32-powerpc-freebsd") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +SEARCH_DIR(/usr/lib); +PROVIDE (__stack = 0); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x0; + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.bss : { *(.rela.bss) } + .rela.plt : { *(.rela.plt) } + .rela.sbss : { *(.rela.sbss) } + .rela.sbss2 : { *(.rela.sbss2) } + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + .init : { *(.init) } =0 + .fini : { *(.fini) } =0 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .sbss2 : { *(.sbss2) } + /* Adjust the address for the data segment to the next page up. */ + . = ((. + 0x1000) & ~(0x1000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .got1 : { *(.got1) } + .dynamic : { *(.dynamic) } + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. + The current compiler no longer needs this, but keep it around for 2.7.2 */ + PROVIDE (_GOT2_START_ = .); + .got2 : { *(.got2) } + PROVIDE (__CTOR_LIST__ = .); + .ctors : { *(.ctors) } + PROVIDE (__CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + .dtors : { *(.dtors) } + PROVIDE (__DTOR_END__ = .); + PROVIDE (_FIXUP_START_ = .); + .fixup : { *(.fixup) } + PROVIDE (_FIXUP_END_ = .); + PROVIDE (_GOT2_END_ = .); + PROVIDE (_GOT_START_ = .); + .got : { *(.got) } + .got.plt : { *(.got.plt) } + PROVIDE (_GOT_END_ = .); + _edata = .; + PROVIDE (edata = .); + .sbss : + { + PROVIDE (__sbss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + PROVIDE (__sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + PROVIDE (__bss_start = .); + *(.dynbss) + *(.bss) + *(COMMON) + } + . = ALIGN(4096); + _end = . ; + PROVIDE (end = .); +} + diff --git a/stand/powerpc/ps3/lv1call.S b/stand/powerpc/ps3/lv1call.S new file mode 100644 index 000000000000..a399a9c3bbf6 --- /dev/null +++ b/stand/powerpc/ps3/lv1call.S @@ -0,0 +1,346 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* Hypercall stubs. Note: this is all a hack and should die. */ + +#define hc .long 0x44000022 + +#define LD64_IM(r, highest, higher, high, low) \ + lis r,highest; \ + addi r,r,higher; \ + sldi r,r,32; \ + addis r,r,high; \ + addi r,r,low; + +#define SIMPLE_HVCALL(x, c) \ +.global x; \ +x: \ + mflr %r0; \ + stw %r0,4(%r1); \ + clrldi %r3,%r3,32; \ + clrldi %r4,%r4,32; \ + clrldi %r5,%r5,32; \ + clrldi %r6,%r6,32; \ + clrldi %r7,%r7,32; \ + clrldi %r8,%r8,32; \ + clrldi %r9,%r9,32; \ + clrldi %r10,%r10,32; \ + li %r11,c; \ + hc; \ + extsw %r3,%r3; \ + lwz %r0,4(%r1); \ + mtlr %r0; \ + blr + +SIMPLE_HVCALL(lv1_open_device, 170) +SIMPLE_HVCALL(lv1_close_device, 171) +SIMPLE_HVCALL(lv1_gpu_open, 210) +SIMPLE_HVCALL(lv1_gpu_context_attribute, 225) +SIMPLE_HVCALL(lv1_panic, 255) +SIMPLE_HVCALL(lv1_net_start_tx_dma, 187) +SIMPLE_HVCALL(lv1_net_stop_tx_dma, 188) +SIMPLE_HVCALL(lv1_net_start_rx_dma, 189) +SIMPLE_HVCALL(lv1_net_stop_rx_dma, 190) + +.global lv1_get_physmem +lv1_get_physmem: + mflr %r0 + stw %r0,4(%r1) + stw %r3,-8(%r1) /* Address for maxmem */ + + li %r11,69 /* Get PU ID */ + hc + std %r4,-16(%r1) + + li %r11,74 /* Get LPAR ID */ + hc + std %r4,-24(%r1) + + ld %r3,-24(%r1) + LD64_IM(%r4,0x0000,0x0000,0x6269,0x0000 /* "bi" */) + LD64_IM(%r5,0x7075,0x0000,0x0000,0x0000 /* "pu" */) + ld %r6,-16(%r1) + LD64_IM(%r7,0x726d,0x5f73,0x697a,0x6500 /* "rm_size" */) + li %r11,91 + hc + extsw %r3,%r3 + + lwz %r5,-8(%r1) + std %r4,0(%r5) + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_setup_address_space +lv1_setup_address_space: + mflr %r0 + stw %r0,4(%r1) + + stw %r3,-4(%r1) + stw %r4,-8(%r1) + + li %r3,18 /* PT size: log2(256 KB) */ + li %r4,2 /* Two page sizes */ + li %r5,24 /* Page sizes: (24 << 56) | (16 << 48) */ + sldi %r5,%r5,24 + li %r6,16 + sldi %r6,%r6,16 + or %r5,%r5,%r6 + sldi %r5,%r5,32 + + li %r11,2 /* lv1_construct_virtual_address_space */ + hc + + lwz %r6,-4(%r1) + lwz %r7,-8(%r1) + std %r4,0(%r6) + std %r5,0(%r7) + + /* AS_ID in r4 */ + mr %r3,%r4 + li %r11,7 /* lv1_select_virtual_address_space */ + hc + extsw %r3,%r3 + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_insert_pte +lv1_insert_pte: + mflr %r0 + stw %r0,4(%r1) + + mr %r11,%r4 /* Save R4 */ + + clrldi %r3,%r3,32 + clrldi %r7,%r5,32 + + sldi %r4,%r3,3 /* Convert ptegidx into base PTE slot */ + li %r3,0 /* Current address space */ + ld %r5,0(%r11) + ld %r6,8(%r11) + li %r8,0 /* No other flags */ + + li %r11,158 + hc + extsw %r3,%r3 + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_gpu_context_allocate +lv1_gpu_context_allocate: + mflr %r0 + stw %r0,4(%r1) + stw %r7,-4(%r1) + + sldi %r3,%r3,32 + clrldi %r4,%r4,32 + or %r3,%r3,%r4 + clrldi %r4,%r5,32 + clrldi %r5,%r6,32 + + li %r11,217 + hc + extsw %r3,%r3 + + lwz %r7,-4(%r1) + std %r4,0(%r7) + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_gpu_memory_allocate +lv1_gpu_memory_allocate: + mflr %r0 + stw %r0,4(%r1) + stw %r8,-4(%r1) + stw %r9,-8(%r1) + + li %r11,214 + hc + extsw %r3,%r3 + + lwz %r8,-4(%r1) + lwz %r9,-8(%r1) + std %r4,0(%r8) + std %r5,0(%r9) + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_net_control +lv1_net_control: + mflr %r0 + stw %r0,4(%r1) + stw %r9,-4(%r1) + + li %r11,194 + hc + extsw %r3,%r3 + + lwz %r8,-4(%r1) + std %r4,0(%r8) + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_setup_dma +lv1_setup_dma: + mflr %r0 + stw %r0,4(%r1) + stw %r3,-4(%r1) + stw %r4,-8(%r1) + stw %r5,-12(%r1) + + lwz %r3,-4(%r1) + lwz %r4,-8(%r1) + lis %r5,0x0800 /* 128 MB */ + li %r6,24 /* log2(IO_PAGESIZE) */ + li %r7,0 /* flags */ + li %r11,174 /* lv1_allocate_device_dma_region */ + hc + extsw %r3,%r3 + cmpdi %r3,0 + bne 1f + std %r4,-24(%r1) + + lwz %r3,-4(%r1) + lwz %r4,-8(%r1) + li %r5,0 + ld %r6,-24(%r1) + lis %r7,0x0800 /* 128 MB */ + lis %r8,0xf800 /* flags */ + sldi %r8,%r8,32 + li %r11,176 /* lv1_map_device_dma_region */ + hc + extsw %r3,%r3 + + lwz %r9,-12(%r1) + ld %r6,-24(%r1) + std %r6,0(%r9) + +1: lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_get_repository_node_value +lv1_get_repository_node_value: + mflr %r0 + stw %r0,4(%r1) + + sldi %r3,%r3,32 + clrldi %r4,%r4,32 + or %r3,%r3,%r4 + sldi %r4,%r5,32 + clrldi %r5,%r6,32 + or %r4,%r4,%r5 + sldi %r5,%r7,32 + clrldi %r6,%r8,32 + or %r5,%r5,%r6 + sldi %r6,%r9,32 + clrldi %r7,%r10,32 + or %r6,%r6,%r7 + lwz %r7,8(%r1) + lwz %r8,12(%r1) + sldi %r7,%r7,32 + or %r7,%r7,%r8 + + li %r11,91 + hc + extsw %r3,%r3 + + lwz %r6,16(%r1) + std %r4,0(%r6) + lwz %r6,20(%r1) + std %r5,0(%r6) + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_storage_read +lv1_storage_read: + mflr %r0 + stw %r0,4(%r1) + + sldi %r3,%r3,32 + clrldi %r4,%r4,32 + or %r3,%r3,%r4 + sldi %r4,%r5,32 + clrldi %r5,%r6,32 + or %r4,%r4,%r5 + sldi %r5,%r7,32 + clrldi %r6,%r8,32 + or %r5,%r5,%r6 + sldi %r6,%r9,32 + clrldi %r7,%r10,32 + or %r6,%r6,%r7 + ld %r7,8(%r1) + ld %r8,16(%r1) + + li %r11,245 + hc + extsw %r3,%r3 + + lwz %r5,24(%r1) + std %r4,0(%r5) + + lwz %r0,4(%r1) + mtlr %r0 + blr + +.global lv1_storage_check_async_status +lv1_storage_check_async_status: + mflr %r0 + stw %r0,4(%r1) + stw %r7,-4(%r1) + + sldi %r3,%r3,32 + clrldi %r4,%r4,32 + or %r3,%r3,%r4 + sldi %r4,%r5,32 + clrldi %r5,%r6,32 + or %r4,%r4,%r5 + + li %r11,254 + hc + extsw %r3,%r3 + + lwz %r5,-4(%r1) + std %r4,0(%r5) + + lwz %r0,4(%r1) + mtlr %r0 + blr diff --git a/stand/powerpc/ps3/lv1call.h b/stand/powerpc/ps3/lv1call.h new file mode 100644 index 000000000000..fb8044825bd0 --- /dev/null +++ b/stand/powerpc/ps3/lv1call.h @@ -0,0 +1,80 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PS3_LV1CALL_H +#define _PS3_LV1CALL_H + +#include <machine/pte.h> + +int lv1_get_physmem(uint64_t *maxmem); +int lv1_setup_address_space(uint64_t *as_id, uint64_t *ptsize); +int lv1_insert_pte(u_int ptegidx, struct lpte *pte, int lockflags); +int lv1_panic(int reboot); + +#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET 0x0100 +#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x0101 +#define L1GPU_DISPLAY_SYNC_HSYNC 1 +#define L1GPU_DISPLAY_SYNC_VSYNC 2 +#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x0102 + +int lv1_gpu_open(int); +int lv1_gpu_context_attribute(int context, int op, int, int, int, int); +int lv1_gpu_memory_allocate(int size, int, int, int, int, uint64_t *handle, + uint64_t *paddr); +int lv1_gpu_context_allocate(uint64_t handle, int, uint64_t *context); + +int lv1_open_device(int, int, int /* 0 */); +int lv1_close_device(int, int); +int lv1_setup_dma(int, int, uint64_t *dmabase); + +#define GELIC_GET_MAC_ADDRESS 0x0001 +#define GELIC_GET_LINK_STATUS 0x0002 +#define GELIC_LINK_UP 0x0001 +#define GELIC_FULL_DUPLEX 0x0002 +#define GELIC_AUTO_NEG 0x0004 +#define GELIC_SPEED_10 0x0010 +#define GELIC_SPEED_100 0x0020 +#define GELIC_SPEED_1000 0x0040 +#define GELIC_GET_VLAN_ID 0x0004 + +int lv1_net_init(int bus, int dev); +int lv1_net_control(int bus, int dev, int, int, int, int, uint64_t *); +int lv1_net_start_tx_dma(int bus, int dev, uint32_t addr, int); +int lv1_net_start_rx_dma(int bus, int dev, uint32_t addr, int); +int lv1_net_stop_tx_dma(int bus, int dev, int); +int lv1_net_stop_rx_dma(int bus, int dev, int); + +int lv1_get_repository_node_value(uint64_t lpar_id, uint64_t n1, uint64_t n2, + uint64_t n3, uint64_t n4, uint64_t *v1, uint64_t *v2); + +int lv1_storage_read(uint64_t dev_id, uint64_t region_id, uint64_t start_sector, + uint64_t sector_count, uint64_t flags, uint64_t buf, uint64_t *tag); +int lv1_storage_check_async_status(uint64_t dev_id, uint64_t tag, + uint64_t *status); + +#endif + diff --git a/stand/powerpc/ps3/main.c b/stand/powerpc/ps3/main.c new file mode 100644 index 000000000000..be8708aadefa --- /dev/null +++ b/stand/powerpc/ps3/main.c @@ -0,0 +1,248 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> + +#define _KERNEL +#include <machine/cpufunc.h> + +#include "bootstrap.h" +#include "lv1call.h" +#include "ps3.h" +#include "ps3devdesc.h" + +struct arch_switch archsw; +extern void *_end; + +extern char bootprog_info[]; + +int ps3_getdev(void **vdev, const char *devspec, const char **path); +ssize_t ps3_copyin(const void *src, vm_offset_t dest, const size_t len); +ssize_t ps3_copyout(vm_offset_t src, void *dest, const size_t len); +ssize_t ps3_readin(const int fd, vm_offset_t dest, const size_t len); +int ps3_autoload(void); +int ps3_setcurrdev(struct env_var *ev, int flags, const void *value); + +static uint64_t basetb; + +int +main(void) +{ + uint64_t maxmem = 0; + void *heapbase; + int i, err; + struct ps3_devdesc currdev; + struct open_file f; + + lv1_get_physmem(&maxmem); + + ps3mmu_init(maxmem); + + /* + * Set up console. + */ + cons_probe(); + + /* + * Set the heap to one page after the end of the loader. + */ + heapbase = (void *)(maxmem - 0x80000); + setheap(heapbase, maxmem); + + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) { + if (devsw[i]->dv_init != NULL) { + err = (devsw[i]->dv_init)(); + if (err) { + printf("\n%s: initialization failed err=%d\n", + devsw[i]->dv_name, err); + continue; + } + } + + currdev.d_dev = devsw[i]; + currdev.d_type = currdev.d_dev->dv_type; + + if (strcmp(devsw[i]->dv_name, "cd") == 0) { + f.f_devdata = &currdev; + currdev.d_unit = 0; + + if (devsw[i]->dv_open(&f, &currdev) == 0) + break; + } + + if (strcmp(devsw[i]->dv_name, "disk") == 0) { + f.f_devdata = &currdev; + currdev.d_unit = 3; + currdev.d_disk.pnum = 1; + currdev.d_disk.ptype = PTYPE_GPT; + + if (devsw[i]->dv_open(&f, &currdev) == 0) + break; + } + + if (strcmp(devsw[i]->dv_name, "net") == 0) + break; + } + + if (devsw[i] == NULL) + panic("No boot device found!"); + else + printf("Boot device: %s\n", devsw[i]->dv_name); + + /* + * Get timebase at boot. + */ + basetb = mftb(); + + archsw.arch_getdev = ps3_getdev; + archsw.arch_copyin = ps3_copyin; + archsw.arch_copyout = ps3_copyout; + archsw.arch_readin = ps3_readin; + archsw.arch_autoload = ps3_autoload; + + printf("\n%s", bootprog_info); + printf("Memory: %lldKB\n", maxmem / 1024); + + env_setenv("currdev", EV_VOLATILE, ps3_fmtdev(&currdev), + ps3_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, ps3_fmtdev(&currdev), env_noset, + env_nounset); + setenv("LINES", "24", 1); + setenv("hw.platform", "ps3", 1); + + interact(NULL); /* doesn't return */ + + return (0); +} + +void +ppc_exception(int code, vm_offset_t where, register_t msr) +{ + mtmsr(PSL_IR | PSL_DR | PSL_RI); + printf("Exception %x at %#lx!\n", code, where); + printf("Rebooting in 5 seconds...\n"); + delay(10000000); + lv1_panic(1); +} + +const u_int ns_per_tick = 12; + +void +exit(int code) +{ + lv1_panic(code); +} + +void +delay(int usecs) +{ + uint64_t tb,ttb; + tb = mftb(); + + ttb = tb + howmany(usecs * 1000, ns_per_tick); + while (tb < ttb) + tb = mftb(); +} + +time_t +getsecs(void) +{ + return ((time_t)((mftb() - basetb)*ns_per_tick/1000000000)); +} + +time_t +time(time_t *tloc) +{ + time_t rv; + + rv = getsecs(); + if (tloc != NULL) + *tloc = rv; + + return (rv); +} + +ssize_t +ps3_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + bcopy(src, (void *)dest, len); + return (len); +} + +ssize_t +ps3_copyout(vm_offset_t src, void *dest, const size_t len) +{ + bcopy((void *)src, dest, len); + return (len); +} + +ssize_t +ps3_readin(const int fd, vm_offset_t dest, const size_t len) +{ + void *buf; + size_t resid, chunk, get; + ssize_t got; + vm_offset_t p; + + p = dest; + + chunk = min(PAGE_SIZE, len); + buf = malloc(chunk); + if (buf == NULL) { + printf("ps3_readin: buf malloc failed\n"); + return(0); + } + + for (resid = len; resid > 0; resid -= got, p += got) { + get = min(chunk, resid); + got = read(fd, buf, get); + if (got <= 0) { + if (got < 0) + printf("ps3_readin: read failed\n"); + break; + } + + bcopy(buf, (void *)p, got); + } + + free(buf); + return (len - resid); +} + +int +ps3_autoload(void) +{ + + return (0); +} + diff --git a/stand/powerpc/ps3/metadata.c b/stand/powerpc/ps3/metadata.c new file mode 100644 index 000000000000..6f29c5774ef3 --- /dev/null +++ b/stand/powerpc/ps3/metadata.c @@ -0,0 +1,333 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> +#include <sys/boot.h> + +#include <machine/metadata.h> + +#include "bootstrap.h" + +int +md_getboothowto(char *kargs) +{ + char *cp; + int howto; + int active; + int i; + + /* Parse kargs */ + howto = 0; + if (kargs != NULL) { + cp = kargs; + active = 0; + while (*cp != 0) { + if (!active && (*cp == '-')) { + active = 1; + } else if (active) + switch (*cp) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'C': + howto |= RB_CDROM; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'g': + howto |= RB_GDB; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'v': + howto |= RB_VERBOSE; + break; + default: + active = 0; + break; + } + cp++; + } + } + /* get equivalents from the environment */ + for (i = 0; howto_names[i].ev != NULL; i++) + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + if (!strcmp(getenv("console"), "comconsole")) + howto |= RB_SERIAL; + if (!strcmp(getenv("console"), "nullconsole")) + howto |= RB_MUTE; + return(howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as <name>=<value>, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +md_copyenv(vm_offset_t addr) +{ + struct env_var *ep; + + /* traverse the environment */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); + addr += strlen(ep->ev_name); + archsw.arch_copyin("=", addr, 1); + addr++; + if (ep->ev_value != NULL) { + archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); + addr += strlen(ep->ev_value); + } + archsw.arch_copyin("", addr, 1); + addr++; + } + archsw.arch_copyin("", addr, 1); + addr++; + return(addr); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ + +static int align; + +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + archsw.arch_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c) \ + if (c) \ + archsw.arch_copyin(s, a, strlen(s) + 1);\ + a += roundup(strlen(s) + 1, align); \ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + archsw.arch_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), align); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c);\ + COPY32(mm->md_size, a, c); \ + if (c) \ + archsw.arch_copyin(mm->md_data, a, mm->md_size);\ + a += roundup(mm->md_size, align); \ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +vm_offset_t +md_copymodules(vm_offset_t addr, int kern64) +{ + struct preloaded_file *fp; + struct file_metadata *md; + uint64_t scratch64; + int c; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + if (kern64) { + scratch64 = fp->f_addr; + MOD_ADDR(addr, scratch64, c); + scratch64 = fp->f_size; + MOD_SIZE(addr, scratch64, c); + } else { + MOD_ADDR(addr, fp->f_addr, c); + MOD_SIZE(addr, fp->f_size, c); + } + for (md = fp->f_metadata; md != NULL; md = md->md_next) { + if (!(md->md_type & MODINFOMD_NOCOPY)) { + MOD_METADATA(addr, md, c); + } + } + } + MOD_END(addr, c); + return(addr); +} + +/* + * Load the information expected by a powerpc kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +md_load_dual(char *args, vm_offset_t *modulep, int kern64) +{ + struct preloaded_file *kfp; + struct preloaded_file *xp; + struct file_metadata *md; + vm_offset_t kernend; + vm_offset_t addr; + vm_offset_t envp; + vm_offset_t size; + uint64_t scratch64; + char *rootdevname; + int howto; + + align = kern64 ? 8 : 4; + howto = md_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + if (rootdevname == NULL) + rootdevname = getenv("currdev"); + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(rootdevname); + + /* find the last module in the chain */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* copy our environment */ + envp = addr; + addr = md_copyenv(addr); + + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + kernend = 0; + kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + if (kern64) { + scratch64 = envp; + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); + scratch64 = kernend; + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64); + } else { + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + } + + *modulep = addr; + size = md_copymodules(0, kern64); + kernend = roundup(addr + size, PAGE_SIZE); + + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + if (kern64) { + scratch64 = kernend; + bcopy(&scratch64, md->md_data, sizeof scratch64); + } else { + bcopy(&kernend, md->md_data, sizeof kernend); + } + + (void)md_copymodules(addr, kern64); + + return(0); +} + +int +md_load(char *args, vm_offset_t *modulep) +{ + return (md_load_dual(args, modulep, 0)); +} + +int +md_load64(char *args, vm_offset_t *modulep) +{ + return (md_load_dual(args, modulep, 1)); +} + diff --git a/stand/powerpc/ps3/ppc64_elf_freebsd.c b/stand/powerpc/ps3/ppc64_elf_freebsd.c new file mode 100644 index 000000000000..3eb991e10ae9 --- /dev/null +++ b/stand/powerpc/ps3/ppc64_elf_freebsd.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2001 Benno Rice <benno@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 + +#include <sys/param.h> +#include <sys/linker.h> + +#include <machine/metadata.h> +#include <machine/elf.h> + +#include <stand.h> + +#include "bootstrap.h" + +extern char end[]; +extern vm_offset_t reloc; /* From <arch>/conf.c */ + +int +ppc64_elf_loadfile(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + int r; + + r = __elfN(loadfile)(filename, dest, result); + if (r != 0) + return (r); + + /* + * No need to sync the icache for modules: this will + * be done by the kernel after relocation. + */ + if (!strcmp((*result)->f_type, "elf kernel")) + __syncicache((void *) (*result)->f_addr, (*result)->f_size); + return (0); +} + +int +ppc64_elf_exec(struct preloaded_file *fp) +{ + struct file_metadata *fmp; + vm_offset_t mdp; + Elf_Ehdr *e; + int error; + int (*entry)(u_long, u_long, u_long, void *, u_long); + + if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) { + return(EFTYPE); + } + e = (Elf_Ehdr *)&fmp->md_data; + + /* Handle function descriptor for ELFv1 kernels */ + if ((e->e_flags & 3) == 2) + entry = e->e_entry; + else + entry = (void *)(uintptr_t)(*(uint64_t *)e->e_entry); + + if ((error = md_load64(fp->f_args, &mdp)) != 0) + return (error); + + printf("Kernel entry at %p ...\n", entry); + + dev_cleanup(); + + entry(0 /* FDT */, 0 /* Phys. mem offset */, 0 /* OF entry */, + (void *)mdp, sizeof(mdp)); + + panic("exec returned"); +} + +struct file_format ppc_elf64 = +{ + ppc64_elf_loadfile, + ppc64_elf_exec +}; diff --git a/stand/powerpc/ps3/ps3.h b/stand/powerpc/ps3/ps3.h new file mode 100644 index 000000000000..1a770029a5c0 --- /dev/null +++ b/stand/powerpc/ps3/ps3.h @@ -0,0 +1,35 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PS3_H +#define _PS3_H + +int ps3mmu_init(int maxmem); +int ps3mmu_map(uint64_t va, uint64_t pa); +void *ps3mmu_mapdev(uint64_t pa, size_t length); + +#endif diff --git a/stand/powerpc/ps3/ps3bus.h b/stand/powerpc/ps3/ps3bus.h new file mode 100644 index 000000000000..a3b20f3bd88f --- /dev/null +++ b/stand/powerpc/ps3/ps3bus.h @@ -0,0 +1,41 @@ +/*- + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PS3_BUS_H +#define _PS3_BUS_H + +enum { + PS3_BUS_TYPE_STOR = 5, +}; + +enum { + PS3_DEV_TYPE_STOR_DISK = 0, + PS3_DEV_TYPE_STOR_CDROM = 5, + PS3_DEV_TYPE_STOR_FLASH = 14, +}; + +#endif diff --git a/stand/powerpc/ps3/ps3cdrom.c b/stand/powerpc/ps3/ps3cdrom.c new file mode 100644 index 000000000000..d8d41fde49af --- /dev/null +++ b/stand/powerpc/ps3/ps3cdrom.c @@ -0,0 +1,156 @@ +/*- + * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/endian.h> +#include <machine/stdarg.h> +#include <stand.h> + +#include "bootstrap.h" +#include "ps3bus.h" +#include "ps3devdesc.h" +#include "ps3stor.h" + +#define dev_printf(dev, fmt, args...) \ + printf("%s%d: " fmt "\n", dev->d_dev->dv_name, dev->d_unit, ##args) + +#ifdef CD_DEBUG +#define DEBUG(fmt, args...) printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args) +#else +#define DEBUG(fmt, args...) +#endif + +static int ps3cdrom_init(void); +static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); +static int ps3cdrom_open(struct open_file *f, ...); +static int ps3cdrom_close(struct open_file *f); +static int ps3cdrom_print(int verbose); + +struct devsw ps3cdrom = { + "cd", + DEVT_CD, + ps3cdrom_init, + ps3cdrom_strategy, + ps3cdrom_open, + ps3cdrom_close, + noioctl, + ps3cdrom_print, +}; + +static struct ps3_stordev stor_dev; + +static int ps3cdrom_init(void) +{ + int err; + + err = ps3stor_setup(&stor_dev, PS3_DEV_TYPE_STOR_CDROM); + if (err) + return err; + + return 0; +} + +static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize) +{ + struct ps3_devdesc *dev = (struct ps3_devdesc *) devdata; + int err; + + DEBUG("d_unit=%u dblk=%llu size=%u", dev->d_unit, dblk, size); + + flag &= F_MASK; + if (flag != F_READ) { + dev_printf(dev, "write operation is not supported!"); + return EROFS; + } + + if (dblk % (stor_dev.sd_blksize / DEV_BSIZE) != 0) + return EINVAL; + + dblk /= (stor_dev.sd_blksize / DEV_BSIZE); + + if (size % stor_dev.sd_blksize) { + dev_printf(dev, + "size=%u is not multiple of device block size=%llu", size, + stor_dev.sd_blksize); + return EINVAL; + } + + if (rsize) + *rsize = 0; + + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, dblk, + size / stor_dev.sd_blksize, 0, buf); + + if (!err && rsize) + *rsize = size; + + if (err) + dev_printf(dev, + "read operation failed dblk=%llu size=%d err=%d", dblk, + size, err); + + return err; +} + +static int ps3cdrom_open(struct open_file *f, ...) +{ + char buf[2048]; + va_list ap; + struct ps3_devdesc *dev; + int err; + + va_start(ap, f); + dev = va_arg(ap, struct ps3_devdesc *); + va_end(ap); + + if (dev->d_unit > 0) { + dev_printf(dev, "attempt to open nonexistent disk"); + return ENXIO; + } + + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, 16, 1, 0, buf); + if (err) + return EIO; + + /* Do not attach if not ISO9660 (workaround for buggy firmware) */ + if (memcmp(buf, "\001CD001", 6) != 0) + return EIO; + + return 0; +} + +static int ps3cdrom_close(struct open_file *f) +{ + return 0; +} + +static int ps3cdrom_print(int verbose) +{ + return (0); +} diff --git a/stand/powerpc/ps3/ps3cons.c b/stand/powerpc/ps3/ps3cons.c new file mode 100644 index 000000000000..fa9ef321c62a --- /dev/null +++ b/stand/powerpc/ps3/ps3cons.c @@ -0,0 +1,173 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "bootstrap.h" +#include "font.h" +#include "lv1call.h" +#include "ps3.h" + +#define FONT_SIZE 14 +#define FONT dflt_font_14 +#define XMARGIN 40 +#define YMARGIN 30 +#define BG_COLOR 0x00000000 +#define FG_COLOR 0xffffffff + +#define FB_SIZE (16*1024*1024) +uint64_t fb_paddr = 0; +uint32_t *fb_vaddr; + +int fb_width, fb_height; +int x, y; + +static void ps3cons_probe(struct console *cp); +static int ps3cons_init(int arg); +static void ps3cons_putchar(int c); +static int ps3cons_getchar(); +static int ps3cons_poll(); + +struct console ps3console = { + "ps3", + "Playstation 3 Framebuffer", + 0, + ps3cons_probe, + ps3cons_init, + ps3cons_putchar, + ps3cons_getchar, + ps3cons_poll, +}; + +static void +ps3cons_probe(struct console *cp) +{ + /* XXX: Get from HV */ + fb_width = 720; + fb_height = 480; + + cp->c_flags |= C_PRESENTIN|C_PRESENTOUT; +} + +static int +ps3cons_init(int arg) +{ + uint64_t fbhandle, fbcontext; + int i; + + lv1_gpu_open(0); + lv1_gpu_context_attribute(0, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET, + 0,0,0,0); + lv1_gpu_context_attribute(0, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET, + 0,0,1,0); + lv1_gpu_context_attribute(0, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, + 0,L1GPU_DISPLAY_SYNC_VSYNC,0,0); + lv1_gpu_context_attribute(0, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, + 1,L1GPU_DISPLAY_SYNC_VSYNC,0,0); + lv1_gpu_memory_allocate(FB_SIZE, 0, 0, 0, 0, &fbhandle, &fb_paddr); + lv1_gpu_context_allocate(fbhandle, 0, &fbcontext); + + lv1_gpu_context_attribute(fbcontext, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 0, 0, 0, 0); + lv1_gpu_context_attribute(fbcontext, + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 1, 0, 0, 0); + + fb_vaddr = ps3mmu_mapdev(fb_paddr, FB_SIZE); + + x = y = 0; + + /* Blank console */ + for (i = 0; i < fb_width*fb_height; i++) + fb_vaddr[i] = BG_COLOR; + + return (0); +} + +static void +ps3cons_putchar(int c) +{ + uint32_t fg, bg; + uint32_t *addr; + int i, j, k; + u_char *p; + + fg = FG_COLOR; + bg = BG_COLOR; + + switch (c) { + case '\0': + break; + case '\r': + x = 0; + break; + case '\n': + y += FONT_SIZE; + break; + case '\b': + x = max(0, x - 8); + break; + default: + /* Wrap long lines */ + if (x + XMARGIN + FONT_SIZE > fb_width - XMARGIN) { + y += FONT_SIZE; + x = 0; + } + + if (y + YMARGIN + FONT_SIZE > fb_height - YMARGIN) + y = 0; + + addr = fb_vaddr + (y + YMARGIN)*fb_width + (x + XMARGIN); + p = FONT + c*FONT_SIZE; + + for (i = 0; i < FONT_SIZE; i++) { + for (j = 0, k = 7; j < 8; j++, k--) { + if ((p[i] & (1 << k)) == 0) + *(addr + j) = bg; + else + *(addr + j) = fg; + } + + addr += fb_width; + } + + x += 8; + break; + } +} + +static int +ps3cons_getchar() +{ + return (-1); +} + +static int +ps3cons_poll() +{ + return (0); +} + diff --git a/stand/powerpc/ps3/ps3devdesc.h b/stand/powerpc/ps3/ps3devdesc.h new file mode 100644 index 000000000000..5a6e52ff5277 --- /dev/null +++ b/stand/powerpc/ps3/ps3devdesc.h @@ -0,0 +1,53 @@ +/*- + * Copyright (C) 2000 Benno Rice. + * Copyright (C) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PS3_DEV_DESC_H +#define _PS3_DEV_DESC_H + +/* Note: Must match the 'struct devdesc' in bootstrap.h */ +struct ps3_devdesc { + struct devsw *d_dev; + int d_type; + int d_unit; + + union { + struct { + void *data; + int pnum; + int ptype; + } disk; + } d_kind; +}; + +#define d_disk d_kind.disk + +#define PTYPE_BSDLABEL 1 +#define PTYPE_GPT 2 + +#endif diff --git a/stand/powerpc/ps3/ps3disk.c b/stand/powerpc/ps3/ps3disk.c new file mode 100644 index 000000000000..c33a023e70a6 --- /dev/null +++ b/stand/powerpc/ps3/ps3disk.c @@ -0,0 +1,315 @@ +/*- + * Copyright (C) 2008 Semihalf, Rafal Jaworowski + * Copyright (C) 2009 Semihalf, Piotr Ziecik + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/endian.h> +#include <machine/stdarg.h> +#include <stand.h> +#include <uuid.h> + +#define FSTYPENAMES +#include <sys/disklabel.h> +#include <sys/diskmbr.h> +#include <sys/gpt.h> + +#include "bootstrap.h" +#include "ps3bus.h" +#include "ps3devdesc.h" +#include "ps3stor.h" + +#define dev_printf(dev, fmt, args...) \ + printf("%s%d: " fmt "\n" , dev->d_dev->dv_name, dev->d_unit, ##args) + +#ifdef DISK_DEBUG +#define DEBUG(fmt, args...) printf("%s:%d: " fmt "\n" , __func__ , __LINE__, ##args) +#else +#define DEBUG(fmt, args...) +#endif + +struct open_dev; + +static int ps3disk_open_gpt(struct ps3_devdesc *dev, struct open_dev *od); +static void ps3disk_uuid_letoh(uuid_t *uuid); + +static int ps3disk_init(void); +static int ps3disk_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); +static int ps3disk_open(struct open_file *f, ...); +static int ps3disk_close(struct open_file *f); +static int ps3disk_print(int verbose); + +struct devsw ps3disk = { + "disk", + DEVT_DISK, + ps3disk_init, + ps3disk_strategy, + ps3disk_open, + ps3disk_close, + noioctl, + ps3disk_print, +}; + +struct gpt_part { + int gp_index; + uuid_t gp_type; + uint64_t gp_start; + uint64_t gp_end; +}; + +struct open_dev { + uint64_t od_start; + + union { + struct { + int nparts; + struct gpt_part *parts; + } gpt; + } od_kind; +}; + +#define od_gpt_nparts od_kind.gpt.nparts +#define od_gpt_parts od_kind.gpt.parts + +static struct ps3_stordev stor_dev; + +static int ps3disk_init(void) +{ + int err; + + err = ps3stor_setup(&stor_dev, PS3_DEV_TYPE_STOR_DISK); + if (err) + return err; + + return 0; +} + +static int ps3disk_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize) +{ + struct ps3_devdesc *dev = (struct ps3_devdesc *) devdata; + struct open_dev *od = (struct open_dev *) dev->d_disk.data; + int err; + + flag &= F_MASK; + if (flag != F_READ) { + dev_printf(dev, "write operation is not supported!\n"); + return EROFS; + } + + if (size % stor_dev.sd_blksize) { + dev_printf(dev, "size=%u is not multiple of device block size=%llu\n", + size, stor_dev.sd_blksize); + return EIO; + } + + if (rsize) + *rsize = 0; + + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, od->od_start + dblk, + size / stor_dev.sd_blksize, 0, buf); + + if (!err && rsize) + *rsize = size; + + if (err) + dev_printf(dev, "read operation failed dblk=%llu size=%d err=%d\n", + dblk, size, err); + + return err; +} + +static int ps3disk_open(struct open_file *f, ...) +{ + va_list ap; + struct ps3_devdesc *dev; + struct open_dev *od; + int err; + + va_start(ap, f); + dev = va_arg(ap, struct ps3_devdesc *); + va_end(ap); + + od = malloc(sizeof(struct open_dev)); + if (!od) { + dev_printf(dev, "couldn't allocate memory for new open_dev\n"); + return ENOMEM; + } + + err = ps3disk_open_gpt(dev, od); + + if (err) { + dev_printf(dev, "couldn't open GPT disk error=%d\n", err); + free(od); + } else { + ((struct ps3_devdesc *) (f->f_devdata))->d_disk.data = od; + } + + return err; +} + +static int ps3disk_close(struct open_file *f) +{ + struct ps3_devdesc *dev = f->f_devdata; + struct open_dev *od = dev->d_disk.data; + + if (dev->d_disk.ptype == PTYPE_GPT && od->od_gpt_nparts) + free(od->od_gpt_parts); + + free(od); + + dev->d_disk.data = NULL; + + return 0; +} + +static int ps3disk_print(int verbose) +{ + return (0); +} + +static int ps3disk_open_gpt(struct ps3_devdesc *dev, struct open_dev *od) +{ + char buf[512]; + struct gpt_hdr *hdr; + struct gpt_ent *ent; + daddr_t slba, elba, lba; + int nparts, eps, i, part, err; + + od->od_gpt_nparts = 0; + od->od_gpt_parts = NULL; + + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, 0, 1, 0, buf); + if (err) { + err = EIO; + goto out; + } + + if (le16toh(*((uint16_t *) (buf + DOSMAGICOFFSET))) != DOSMAGIC) { + err = ENXIO; + goto out; + } + + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, 1, 1, 0, buf); + if (err) { + err = EIO; + goto out; + } + + hdr = (struct gpt_hdr *) buf; + + if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) || + le64toh(hdr->hdr_lba_self) != 1 || le32toh(hdr->hdr_revision) < 0x00010000 || + le32toh(hdr->hdr_entsz) < sizeof(struct gpt_ent) || + stor_dev.sd_blksize % le32toh(hdr->hdr_entsz) != 0) { + err = ENXIO; + goto out; + } + + nparts = 0; + eps = stor_dev.sd_blksize / le32toh(hdr->hdr_entsz); + slba = le64toh(hdr->hdr_lba_table); + elba = slba + le32toh(hdr->hdr_entries) / eps; + + for (lba = slba; lba < elba; lba++) { + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, lba, 1, 0, buf); + if (err) { + err = EIO; + goto out; + } + + ent = (struct gpt_ent *) buf; + + for (i = 0; i < eps; i++) { + if (uuid_is_nil(&ent[i].ent_type, NULL) || + le64toh(ent[i].ent_lba_start) == 0 || + le64toh(ent[i].ent_lba_end) < le64toh(ent[i].ent_lba_start)) + continue; + + nparts++; + } + } + + if (nparts) { + od->od_gpt_nparts = nparts; + + od->od_gpt_parts = malloc(nparts * sizeof(struct gpt_part)); + if (!od->od_gpt_parts) { + err = ENOMEM; + goto out; + } + + for (lba = slba, part = 0; lba < elba; lba++) { + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, lba, 1, 0, buf); + if (err) { + err = EIO; + goto out; + } + + ent = (struct gpt_ent *) buf; + + for (i = 0; i < eps; i++) { + if (uuid_is_nil(&ent[i].ent_type, NULL) || + le64toh(ent[i].ent_lba_start) == 0 || + le64toh(ent[i].ent_lba_end) < le64toh(ent[i].ent_lba_start)) + continue; + + od->od_gpt_parts[part].gp_index = (lba - slba) * eps + i + 1; + od->od_gpt_parts[part].gp_type = ent[i].ent_type; + od->od_gpt_parts[part].gp_start = le64toh(ent[i].ent_lba_start); + od->od_gpt_parts[part].gp_end = le64toh(ent[i].ent_lba_end); + ps3disk_uuid_letoh(&od->od_gpt_parts[part].gp_type); + part++; + } + } + } + + dev->d_disk.ptype = PTYPE_GPT; + + if (od->od_gpt_nparts && !dev->d_disk.pnum) + dev->d_disk.pnum = od->od_gpt_parts[0].gp_index; + + for (i = 0; i < od->od_gpt_nparts; i++) + if (od->od_gpt_parts[i].gp_index == dev->d_disk.pnum) + od->od_start = od->od_gpt_parts[i].gp_start; + + err = 0; + +out: + + if (err && od->od_gpt_parts) + free(od->od_gpt_parts); + + return err; +} + +static void ps3disk_uuid_letoh(uuid_t *uuid) +{ + uuid->time_low = le32toh(uuid->time_low); + uuid->time_mid = le16toh(uuid->time_mid); + uuid->time_hi_and_version = le16toh(uuid->time_hi_and_version); +} diff --git a/stand/powerpc/ps3/ps3mmu.c b/stand/powerpc/ps3/ps3mmu.c new file mode 100644 index 000000000000..08dcf75d2839 --- /dev/null +++ b/stand/powerpc/ps3/ps3mmu.c @@ -0,0 +1,120 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <stdint.h> + +#define _KERNEL +#include <machine/cpufunc.h> +#include <machine/psl.h> +#include <machine/pte.h> +#include <machine/slb.h> +#include <machine/param.h> + +#include "bootstrap.h" +#include "lv1call.h" +#include "ps3.h" + +register_t pteg_count, pteg_mask; +uint64_t as_id; +uint64_t virtual_avail; + +int +ps3mmu_map(uint64_t va, uint64_t pa) +{ + struct lpte pt; + int shift; + uint64_t vsid, ptegidx; + + if (pa < 0x8000000) { /* Phys mem? */ + pt.pte_hi = LPTE_BIG; + pt.pte_lo = LPTE_M; + shift = 24; + vsid = 0; + } else { + pt.pte_hi = 0; + pt.pte_lo = LPTE_I | LPTE_G | LPTE_M | LPTE_NOEXEC; + shift = ADDR_PIDX_SHFT; + vsid = 1; + } + + pt.pte_hi |= (vsid << LPTE_VSID_SHIFT) | + (((uint64_t)(va & ADDR_PIDX) >> ADDR_API_SHFT64) & LPTE_API); + pt.pte_lo |= pa; + ptegidx = vsid ^ (((uint64_t)va & ADDR_PIDX) >> shift); + + pt.pte_hi |= LPTE_LOCKED | LPTE_VALID; + ptegidx &= pteg_mask; + + return (lv1_insert_pte(ptegidx, &pt, LPTE_LOCKED)); +} + +void * +ps3mmu_mapdev(uint64_t pa, size_t length) +{ + uint64_t spa; + void *mapstart; + int err; + + mapstart = (void *)(uintptr_t)virtual_avail; + + for (spa = pa; spa < pa + length; spa += PAGE_SIZE) { + err = ps3mmu_map(virtual_avail, spa); + virtual_avail += PAGE_SIZE; + if (err != 0) + return (NULL); + } + + return (mapstart); +} + +int +ps3mmu_init(int maxmem) +{ + uint64_t ptsize; + int i; + + i = lv1_setup_address_space(&as_id, &ptsize); + pteg_count = ptsize / sizeof(struct lpteg); + pteg_mask = pteg_count - 1; + + for (i = 0; i < maxmem; i += 16*1024*1024) + ps3mmu_map(i,i); + + virtual_avail = 0x10000000; + + __asm __volatile ("slbia; slbmte %0, %1; slbmte %2,%3" :: + "r"((0 << SLBV_VSID_SHIFT) | SLBV_L), "r"(0 | SLBE_VALID), + "r"(1 << SLBV_VSID_SHIFT), + "r"((1 << SLBE_ESID_SHIFT) | SLBE_VALID | 1)); + + mtmsr(PSL_IR | PSL_DR | PSL_RI | PSL_ME); + + return (0); +} + diff --git a/stand/powerpc/ps3/ps3net.c b/stand/powerpc/ps3/ps3net.c new file mode 100644 index 000000000000..142eab8243a6 --- /dev/null +++ b/stand/powerpc/ps3/ps3net.c @@ -0,0 +1,278 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> + +#define _KERNEL +#include <machine/cpufunc.h> + +#include <stand.h> +#include <net.h> +#include <netif.h> +#include "bootstrap.h" +#include "lv1call.h" +#include "ps3.h" + +#define GELIC_DESCR_OWNED 0xa0000000 +#define GELIC_CMDSTAT_NOIPSEC 0x00080000 +#define GELIC_CMDSTAT_LAST 0x00040000 +#define GELIC_RXERRORS 0x7def8000 + +#define GELIC_POLL_PERIOD 100 /* microseconds */ + +static int ps3net_probe(struct netif *, void *); +static int ps3net_match(struct netif *, void *); +static void ps3net_init(struct iodesc *, void *); +static int ps3net_get(struct iodesc *, void *, size_t, time_t); +static int ps3net_put(struct iodesc *, void *, size_t); +static void ps3net_end(struct netif *); + +struct netif_stats ps3net_stats[1]; +struct netif_dif ps3net_ifs[] = {{0, 1, ps3net_stats, 0}}; + +/* XXX: Get from firmware, not hardcoding */ +static int busid = 1; +static int devid = 0; +static int vlan; +static uint64_t dma_base; + +struct gelic_dmadesc { + uint32_t paddr; + uint32_t len; + uint32_t next; + uint32_t cmd_stat; + uint32_t result_size; + uint32_t valid_size; + uint32_t data_stat; + uint32_t rxerror; +}; + +struct netif_driver ps3net = { + "net", + ps3net_match, + ps3net_probe, + ps3net_init, + ps3net_get, + ps3net_put, + ps3net_end, + ps3net_ifs, 1 +}; + +static int +ps3net_match(struct netif *nif, void *machdep_hint) +{ + return (1); +} + +static int +ps3net_probe(struct netif *nif, void *machdep_hint) +{ + return (0); +} + +static int +ps3net_put(struct iodesc *desc, void *pkt, size_t len) +{ + volatile static struct gelic_dmadesc txdesc __aligned(32); + volatile static char txbuf[1536] __aligned(128); + size_t sendlen; + int err; + +#if defined(NETIF_DEBUG) + struct ether_header *eh; + + printf("net_put: desc %p, pkt %p, len %d\n", desc, pkt, len); + eh = pkt; + printf("dst: %s ", ether_sprintf(eh->ether_dhost)); + printf("src: %s ", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xffff); +#endif + + while (txdesc.cmd_stat & GELIC_DESCR_OWNED) { + printf("Stalled XMIT!\n"); + delay(10); + } + + /* + * We must add 4 extra bytes to this packet to store the destination + * VLAN. + */ + memcpy(txbuf, pkt, 12); + sendlen = 12; + + if (vlan >= 0) { + sendlen += 4; + ((uint8_t *)txbuf)[12] = 0x81; + ((uint8_t *)txbuf)[13] = 0x00; + ((uint8_t *)txbuf)[14] = vlan >> 8; + ((uint8_t *)txbuf)[15] = vlan & 0xff; + } + memcpy((void *)txbuf + sendlen, pkt + 12, len - 12); + sendlen += len - 12; + + bzero(&txdesc, sizeof(txdesc)); + txdesc.paddr = dma_base + (uint32_t)txbuf; + txdesc.len = sendlen; + txdesc.cmd_stat = GELIC_CMDSTAT_NOIPSEC | GELIC_CMDSTAT_LAST | + GELIC_DESCR_OWNED; + + powerpc_sync(); + + do { + err = lv1_net_start_tx_dma(busid, devid, + dma_base + (uint32_t)&txdesc, 0); + delay(1); + if (err != 0) + printf("TX Error: %d\n",err); + } while (err != 0); + + return (len); +} + +static int +ps3net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +{ + volatile static struct gelic_dmadesc rxdesc __aligned(32); + volatile static char rxbuf[1536] __aligned(128); + int err = 0; + + if (len == 0) + goto restartdma; + + timeout *= 1000000; /* convert to microseconds */ + while (rxdesc.cmd_stat & GELIC_DESCR_OWNED) { + if (timeout < GELIC_POLL_PERIOD) + return (ETIMEDOUT); + delay(GELIC_POLL_PERIOD); + timeout -= GELIC_POLL_PERIOD; + } + + delay(200); + if (rxdesc.rxerror & GELIC_RXERRORS) { + err = -1; + goto restartdma; + } + + /* + * Copy the packet to the receive buffer, leaving out the + * 2 byte VLAN header. + */ + len = min(len, rxdesc.valid_size - 2); + memcpy(pkt, (u_char *)rxbuf + 2, len); + err = len; + +#if defined(NETIF_DEBUG) +{ + struct ether_header *eh; + + printf("net_get: desc %p, pkt %p, len %d\n", desc, pkt, len); + eh = pkt; + printf("dst: %s ", ether_sprintf(eh->ether_dhost)); + printf("src: %s ", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xffff); +} +#endif + +restartdma: + lv1_net_stop_rx_dma(busid, devid, 0); + powerpc_sync(); + + bzero(&rxdesc, sizeof(rxdesc)); + rxdesc.paddr = dma_base + (uint32_t)rxbuf; + rxdesc.len = sizeof(rxbuf); + rxdesc.next = 0; + rxdesc.cmd_stat = GELIC_DESCR_OWNED; + powerpc_sync(); + + lv1_net_start_rx_dma(busid, devid, dma_base + (uint32_t)&rxdesc, 0); + + return (err); +} + +static void +ps3net_init(struct iodesc *desc, void *machdep_hint) +{ + uint64_t mac, val; + int i,err; + + err = lv1_open_device(busid, devid, 0); + + lv1_net_stop_tx_dma(busid, devid, 0); + lv1_net_stop_rx_dma(busid, devid, 0); + + /* + * Wait for link to come up + */ + + for (i = 0; i < 1000; i++) { + lv1_net_control(busid, devid, GELIC_GET_LINK_STATUS, 2, 0, + 0, &val); + if (val & GELIC_LINK_UP) + break; + delay(500); + } + + /* + * Set up DMA IOMMU entries + */ + + err = lv1_setup_dma(busid, devid, &dma_base); + + /* + * Get MAC address and VLAN IDs + */ + + lv1_net_control(busid, devid, GELIC_GET_MAC_ADDRESS, 0, 0, 0, &mac); + bcopy(&((uint8_t *)&mac)[2], desc->myea, sizeof(desc->myea)); + + vlan = -1; + err = lv1_net_control(busid, devid, GELIC_GET_VLAN_ID, 2, 0, + 0, &val); + if (err == 0) + vlan = val; + + /* + * Start RX DMA engine + */ + + ps3net_get(NULL, NULL, 0, 0); +} + +static void +ps3net_end(struct netif *nif) +{ + lv1_close_device(busid, devid); +} + diff --git a/stand/powerpc/ps3/ps3repo.c b/stand/powerpc/ps3/ps3repo.c new file mode 100644 index 000000000000..006476925479 --- /dev/null +++ b/stand/powerpc/ps3/ps3repo.c @@ -0,0 +1,249 @@ +/*- + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <stand.h> + +#include "lv1call.h" +#include "ps3.h" +#include "ps3repo.h" + +static uint64_t make_n1(const char *text, unsigned int index) +{ + uint64_t n1; + + n1 = 0; + strncpy((char *) &n1, text, sizeof(n1)); + n1 = (n1 >> 32) + index; + + return n1; +} + +static uint64_t make_n(const char *text, unsigned int index) +{ + uint64_t n; + + n = 0; + strncpy((char *) &n, text, sizeof(n)); + n = n + index; + + return n; +} + +int ps3repo_read_bus_type(unsigned int bus_index, uint64_t *bus_type) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("type", 0), 0, 0, &v1, &v2); + + *bus_type = v1; + + return err; +} + +int ps3repo_read_bus_id(unsigned int bus_index, uint64_t *bus_id) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("id", 0), 0, 0, &v1, &v2); + + *bus_id = v1; + + return err; +} + +int ps3repo_read_bus_num_dev(unsigned int bus_index, uint64_t *num_dev) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("num_dev", 0), 0, 0, &v1, &v2); + + *num_dev = v1; + + return err; +} + +int ps3repo_read_bus_dev_type(unsigned int bus_index, unsigned int dev_index, uint64_t *dev_type) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("type", 0), 0, &v1, &v2); + + *dev_type = v1; + + return err; +} + +int ps3repo_read_bus_dev_id(unsigned int bus_index, unsigned int dev_index, uint64_t *dev_id) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("id", 0), 0, &v1, &v2); + + *dev_id = v1; + + return err; +} + +int ps3repo_read_bus_dev_blk_size(unsigned int bus_index, unsigned int dev_index, uint64_t *blk_size) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("blk_size", 0), 0, &v1, &v2); + + *blk_size = v1; + + return err; +} + +int ps3repo_read_bus_dev_nblocks(unsigned int bus_index, unsigned int dev_index, uint64_t *nblocks) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("n_blocks", 0), 0, &v1, &v2); + + *nblocks = v1; + + return err; +} + +int ps3repo_read_bus_dev_nregs(unsigned int bus_index, unsigned int dev_index, uint64_t *nregs) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("n_regs", 0), 0, &v1, &v2); + + *nregs = v1; + + return err; +} + +int ps3repo_read_bus_dev_reg_id(unsigned int bus_index, unsigned int dev_index, + unsigned int reg_index, uint64_t *reg_id) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("region", reg_index), make_n("id", 0), &v1, &v2); + + *reg_id = v1; + + return err; +} + +int ps3repo_read_bus_dev_reg_start(unsigned int bus_index, unsigned int dev_index, + unsigned int reg_index, uint64_t *reg_start) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("region", reg_index), make_n("start", 0), &v1, &v2); + + *reg_start = v1; + + return err; +} + +int ps3repo_read_bus_dev_reg_size(unsigned int bus_index, unsigned int dev_index, + unsigned int reg_index, uint64_t *reg_size) +{ + uint64_t v1, v2; + int err; + + err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, make_n1("bus", bus_index), + make_n("dev", dev_index), make_n("region", reg_index), make_n("size", 0), &v1, &v2); + + *reg_size = v1; + + return err; +} + +int ps3repo_find_bus_by_type(uint64_t bus_type, unsigned int *bus_index) +{ + unsigned int i; + uint64_t type; + int err; + + for (i = 0; i < 10; i++) { + err = ps3repo_read_bus_type(i, &type); + if (err) { + *bus_index = (unsigned int) -1; + return err; + } + + if (type == bus_type) { + *bus_index = i; + return 0; + } + } + + *bus_index = (unsigned int) -1; + + return ENODEV; +} + +int ps3repo_find_bus_dev_by_type(unsigned int bus_index, uint64_t dev_type, + unsigned int *dev_index) +{ + unsigned int i; + uint64_t type; + int err; + + for (i = 0; i < 10; i++) { + err = ps3repo_read_bus_dev_type(bus_index, i, &type); + if (err) { + *dev_index = (unsigned int) -1; + return err; + } + + if (type == dev_type) { + *dev_index = i; + return 0; + } + } + + *dev_index = (unsigned int) -1; + + return ENODEV; +} diff --git a/stand/powerpc/ps3/ps3repo.h b/stand/powerpc/ps3/ps3repo.h new file mode 100644 index 000000000000..68001df3509b --- /dev/null +++ b/stand/powerpc/ps3/ps3repo.h @@ -0,0 +1,51 @@ +/*- + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PS3_REPO_H +#define _PS3_REPO_H + +#define PS3_LPAR_ID_PME 1 + +int ps3repo_read_bus_type(unsigned int bus_index, uint64_t *bus_type); +int ps3repo_read_bus_id(unsigned int bus_index, uint64_t *bus_id); +int ps3repo_read_bus_num_dev(unsigned int bus_index, uint64_t *num_dev); +int ps3repo_read_bus_dev_type(unsigned int bus_index, unsigned int dev_index, uint64_t *dev_type); +int ps3repo_read_bus_dev_id(unsigned int bus_index, unsigned int dev_index, uint64_t *dev_id); +int ps3repo_read_bus_dev_blk_size(unsigned int bus_index, unsigned int dev_index, uint64_t *blk_size); +int ps3repo_read_bus_dev_nblocks(unsigned int bus_index, unsigned int dev_index, uint64_t *nblocks); +int ps3repo_read_bus_dev_nregs(unsigned int bus_index, unsigned int dev_index, uint64_t *nregs); +int ps3repo_read_bus_dev_reg_id(unsigned int bus_index, unsigned int dev_index, + unsigned int reg_index, uint64_t *reg_id); +int ps3repo_read_bus_dev_reg_start(unsigned int bus_index, unsigned int dev_index, + unsigned int reg_index, uint64_t *reg_start); +int ps3repo_read_bus_dev_reg_size(unsigned int bus_index, unsigned int dev_index, + unsigned int reg_index, uint64_t *reg_size); +int ps3repo_find_bus_by_type(uint64_t bus_type, unsigned int *bus_index); +int ps3repo_find_bus_dev_by_type(unsigned int bus_index, uint64_t dev_type, + unsigned int *dev_index); + +#endif diff --git a/stand/powerpc/ps3/ps3stor.c b/stand/powerpc/ps3/ps3stor.c new file mode 100644 index 000000000000..bbfc56a7ae2a --- /dev/null +++ b/stand/powerpc/ps3/ps3stor.c @@ -0,0 +1,176 @@ +/*- + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <stand.h> + +#include "bootstrap.h" +#include "lv1call.h" +#include "ps3bus.h" +#include "ps3repo.h" +#include "ps3stor.h" + +int ps3stor_setup(struct ps3_stordev *sd, int type) +{ + unsigned int i; + int err; + + sd->sd_type = type; + + err = ps3repo_find_bus_by_type(PS3_BUS_TYPE_STOR, &sd->sd_busidx); + if (err) + goto out; + + err = ps3repo_read_bus_id(sd->sd_busidx, &sd->sd_busid); + if (err) + goto out; + + err = ps3repo_find_bus_dev_by_type(sd->sd_busidx, type, &sd->sd_devidx); + if (err) + goto out; + + err = ps3repo_read_bus_dev_id(sd->sd_busidx, sd->sd_devidx, + &sd->sd_devid); + if (err) + goto out; + + err = ps3repo_read_bus_dev_blk_size(sd->sd_busidx, sd->sd_devidx, + &sd->sd_blksize); + if (err) + goto out; + + err = ps3repo_read_bus_dev_nblocks(sd->sd_busidx, sd->sd_devidx, + &sd->sd_nblocks); + if (err) + goto out; + + err = ps3repo_read_bus_dev_nregs(sd->sd_busidx, sd->sd_devidx, + &sd->sd_nregs); + if (err) + goto out; + + for (i = 0; i < sd->sd_nregs; i++) { + err = ps3repo_read_bus_dev_reg_id(sd->sd_busidx, sd->sd_devidx, + i, &sd->sd_regs[i].sr_id); + if (err) + goto out; + + err = ps3repo_read_bus_dev_reg_start(sd->sd_busidx, + sd->sd_devidx, i, &sd->sd_regs[i].sr_start); + if (err) + goto out; + + err = ps3repo_read_bus_dev_reg_size(sd->sd_busidx, + sd->sd_devidx, i, &sd->sd_regs[i].sr_size); + if (err) + goto out; + } + + if (!sd->sd_nregs) { + err = ENODEV; + goto out; + } + + err = lv1_open_device(sd->sd_busid, sd->sd_devid, 0); + if (err) + goto out; + + err = lv1_setup_dma(sd->sd_busid, sd->sd_devid, &sd->sd_dmabase); + if (err) + goto close_dev; + + return 0; + +close_dev: + + lv1_close_device(sd->sd_busid, sd->sd_devid); + +out: + + return err; +} + +static char dma_buf[2048] __aligned(2048); + +int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx, + uint64_t start_sector, uint64_t sector_count, uint64_t flags, char *buf) +{ +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) +#define BOUNCE_SECTORS (sizeof(dma_buf) / sd->sd_blksize) +#define ASYNC_STATUS_POLL_PERIOD 100 /* microseconds */ + + struct ps3_storreg *reg = &sd->sd_regs[regidx]; + uint64_t nleft, nread, nsectors; + uint64_t tag, status; + unsigned int timeout; + int err = 0; + + nleft = sector_count; + nread = 0; + + while (nleft) { + nsectors = MIN(nleft, BOUNCE_SECTORS); + + err = lv1_storage_read(sd->sd_devid, reg->sr_id, + start_sector + nread, nsectors, flags, (uint32_t)dma_buf, + &tag); + if (err) + return err; + + timeout = 5000000; /* microseconds */ + + while (1) { + if (timeout < ASYNC_STATUS_POLL_PERIOD) + return ETIMEDOUT; + + err = lv1_storage_check_async_status(sd->sd_devid, tag, + &status); + if (!err && !status) + break; + + delay(ASYNC_STATUS_POLL_PERIOD); + timeout -= ASYNC_STATUS_POLL_PERIOD; + } + + if (status != 0) + return EIO; + + memcpy(buf + nread * sd->sd_blksize, (u_char *)dma_buf, + nsectors * sd->sd_blksize); + nread += nsectors; + nleft -= nsectors; + } + + return err; + +#undef MIN +#undef BOUNCE_SECTORS +#undef ASYNC_STATUS_POLL_PERIOD +} + +void ps3stor_print(struct ps3_stordev *sd) +{ +} diff --git a/stand/powerpc/ps3/ps3stor.h b/stand/powerpc/ps3/ps3stor.h new file mode 100644 index 000000000000..350b716f7aa1 --- /dev/null +++ b/stand/powerpc/ps3/ps3stor.h @@ -0,0 +1,59 @@ +/*- + * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PS3_STOR_H +#define _PS3_STOR_H + +#define PS3_STOR_DEV_MAXREGS 8 + +struct ps3_storreg { + uint64_t sr_id; + uint64_t sr_start; + uint64_t sr_size; +}; + +struct ps3_stordev { + int sd_type; + unsigned int sd_busidx; + unsigned int sd_devidx; + uint64_t sd_busid; + uint64_t sd_devid; + uint64_t sd_blksize; + uint64_t sd_nblocks; + uint64_t sd_nregs; + struct ps3_storreg sd_regs[PS3_STOR_DEV_MAXREGS]; + uint64_t sd_dmabase; +}; + +int ps3stor_setup(struct ps3_stordev *sd, int type); + +int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx, + uint64_t start_sector, uint64_t sector_count, uint64_t flags, char *buf); + +void ps3stor_print(struct ps3_stordev *sd); + +#endif diff --git a/stand/powerpc/ps3/start.S b/stand/powerpc/ps3/start.S new file mode 100644 index 000000000000..570b3f52cc68 --- /dev/null +++ b/stand/powerpc/ps3/start.S @@ -0,0 +1,169 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define LOCORE + +#include <machine/trap.h> + +/* + * KBoot and simulators will start this program from the _start symbol, with + * r3 pointing to a flattened device tree (kexec), r4 the physical address + * at which we were loaded, and r5 0 (kexec) or a pointer to Open Firmware + * (simulator). If r4 is non-zero, the first order of business is relocating + * ourselves to 0. In the kboot case, the PPE secondary thread will enter + * at 0x60. + * + * If started directly by the LV1 hypervisor, we are loaded to address 0 + * and execution on both threads begins at 0x100 (EXC_RST). + */ + +#define CACHELINE_SIZE 128 +#define SPR_CTRL 136 + +/* KBoot thread 0 entry -- do relocation, then jump to main */ +.global _start +_start: + mfmsr %r31 + clrldi %r31,%r31,1 + mtmsrd %r31 + isync + cmpwi %r4,0 + bne relocate_self +relocated_start: + lis %r1,0x100 + bl main + +. = 0x40 +.global secondary_spin_sem +secondary_spin_sem: + .long 0 + +. = 0x60 +thread1_start_kboot: + mfmsr %r31 + clrldi %r31,%r31,1 + mtmsrd %r31 + isync + + ba thread1_start /* kboot copies the first 256 bytes to + * address 0, so we are safe to jump + * (and stay) there */ + +thread1_start: + li %r3,secondary_spin_sem@l +1: lwz %r1,0(%r3) /* Spin on SECONDARY_SPIN_SEM_ADDRESS */ + cmpwi %r1,0 + beq 1b /* If the semaphore is still zero, spin again */ + + /* We have been woken up by thread 0 */ + li %r0,0x100 /* Invalidate reset vector cache line */ + icbi 0,%r0 + isync + sync + ba 0x100 /* Jump to the reset vector */ + +. = EXC_RST +exc_rst: + mfmsr %r31 + clrldi %r31,%r31,1 + mtmsrd %r31 + isync + + mfspr %r3,SPR_CTRL + /* The first two bits of r0 are 01 (thread 1) or 10 (thread 0) */ + cntlzw %r3,%r3 /* Now 0 for thread 0, 1 for thread 1 */ + + cmpwi %r3,0 + bne thread1_start /* Send thread 1 to wait */ + + b relocated_start /* Main entry point for thread 0 */ + +#define EXCEPTION_HANDLER(exc) \ +. = exc; \ + li %r3, exc; \ + mfsrr0 %r4; \ + mfmsr %r5; \ + clrldi %r6,%r5,1; \ + mtmsrd %r6; \ + isync; \ + lis %r1,0x100; \ + bl ppc_exception + +EXCEPTION_HANDLER(EXC_MCHK) +EXCEPTION_HANDLER(EXC_DSI) +EXCEPTION_HANDLER(EXC_DSE) +EXCEPTION_HANDLER(EXC_ISI) +EXCEPTION_HANDLER(EXC_ISE) +EXCEPTION_HANDLER(EXC_EXI) +EXCEPTION_HANDLER(EXC_ALI) +EXCEPTION_HANDLER(EXC_PGM) +EXCEPTION_HANDLER(EXC_FPU) +EXCEPTION_HANDLER(EXC_DECR) +EXCEPTION_HANDLER(EXC_SC) + +relocate_self: + /* We enter this with r4 the physical offset for our relocation */ + lis %r8,_end@ha /* r8: copy length */ + addi %r8,%r8,_end@l + li %r5,0x100 /* r5: dest address */ +1: add %r6,%r4,%r5 /* r6: source address */ + ld %r7,0(%r6) + std %r7,0(%r5) + addi %r5,%r5,8 + cmpw %r5,%r8 + blt 1b + + /* + * Now invalidate the cacheline with the second half of relocate_self, + * and do an absolute branch there in case we overwrote part of + * ourselves. + */ + + lis %r9,relocate_self_cache@ha + addi %r9,%r9,relocate_self_cache@l + dcbst 0,%r9 + sync + icbi 0,%r9 + sync + isync + ba relocate_self_cache + +relocate_self_cache: + /* Now invalidate the icache */ + li %r5,0x100 +2: dcbst 0,%r5 + sync + icbi 0,%r5 + sync + isync + cmpw %r5,%r8 + addi %r5,%r5,CACHELINE_SIZE + blt 2b + + /* All done: absolute jump to relocated entry point */ + ba relocated_start + diff --git a/stand/powerpc/ps3/version b/stand/powerpc/ps3/version new file mode 100644 index 000000000000..fdac54e40aa5 --- /dev/null +++ b/stand/powerpc/ps3/version @@ -0,0 +1,8 @@ +$FreeBSD$ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +0.3: Added GPT support to disk. +0.2: Added disk support. +0.1: Initial PS3/PowerPC version. diff --git a/stand/powerpc/uboot/Makefile b/stand/powerpc/uboot/Makefile new file mode 100644 index 000000000000..d543aceeee4c --- /dev/null +++ b/stand/powerpc/uboot/Makefile @@ -0,0 +1,37 @@ +# $FreeBSD$ + +LOADER_UFS_SUPPORT?= yes +LOADER_CD9660_SUPPORT?= no +LOADER_EXT2FS_SUPPORT?= no +LOADER_NET_SUPPORT?= yes +LOADER_NFS_SUPPORT?= yes +LOADER_TFTP_SUPPORT?= no +LOADER_GZIP_SUPPORT?= no +LOADER_BZIP2_SUPPORT?= no + +.include <bsd.init.mk> + +PROG= ubldr +NEWVERSWHAT= "U-Boot loader" ${MACHINE_ARCH} +INSTALLFLAGS= -b +MAN= + +# Architecture-specific loader code +SRCS= start.S conf.c vers.c +SRCS+= ucmpdi2.c + +# Always add MI sources +HELP_FILES= # Disable +.include "${BOOTSRC}/loader.mk" +.PATH: ${SYSDIR}/libkern + +CFLAGS+= -ffreestanding + +LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.powerpc + +.include "${BOOTSRC}/uboot.mk" + +DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSA} +LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSA} + +.include <bsd.prog.mk> diff --git a/stand/powerpc/uboot/conf.c b/stand/powerpc/uboot/conf.c new file mode 100644 index 000000000000..561238d1ccf7 --- /dev/null +++ b/stand/powerpc/uboot/conf.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "bootstrap.h" +#include "libuboot.h" + +#if defined(LOADER_NET_SUPPORT) +#include "dev_net.h" +#endif + +/* Make sure we have an explicit reference to exit so libsa's panic pulls in the MD exit */ +void (*exitfn)(int) = exit; + +/* + * We could use linker sets for some or all of these, but + * then we would have to control what ended up linked into + * the bootstrap. So it's easier to conditionalise things + * here. + * + * XXX rename these arrays to be consistent and less namespace-hostile + */ + +/* Exported for libstand */ +struct devsw *devsw[] = { +#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT) + &uboot_storage, +#endif +#if defined(LOADER_NET_SUPPORT) + &netdev, +#endif + NULL +}; + +struct fs_ops *file_system[] = { +#if defined(LOADER_UFS_SUPPORT) + &ufs_fsops, +#endif +#if defined(LOADER_CD9660_SUPPORT) + &cd9660_fsops, +#endif +#if defined(LOADER_EXT2FS_SUPPORT) + &ext2fs_fsops, +#endif +#if defined(LOADER_NFS_SUPPORT) + &nfs_fsops, +#endif +#if defined(LOADER_TFTP_SUPPORT) + &tftp_fsops, +#endif +#if defined(LOADER_GZIP_SUPPORT) + &gzipfs_fsops, +#endif +#if defined(LOADER_BZIP2_SUPPORT) + &bzipfs_fsops, +#endif + NULL +}; + +struct netif_driver *netif_drivers[] = { +#if defined(LOADER_NET_SUPPORT) + &uboot_net, +#endif + NULL, +}; + +/* Exported for PowerPC only */ +/* + * Sort formats so that those that can detect based on arguments + * rather than reading the file go first. + */ + +struct file_format *file_formats[] = { + &uboot_elf, + NULL +}; + +/* + * Consoles + */ +extern struct console uboot_console; + +struct console *consoles[] = { + &uboot_console, + NULL +}; diff --git a/stand/powerpc/uboot/ldscript.powerpc b/stand/powerpc/uboot/ldscript.powerpc new file mode 100644 index 000000000000..923838365793 --- /dev/null +++ b/stand/powerpc/uboot/ldscript.powerpc @@ -0,0 +1,138 @@ +/* $FreeBSD$ */ + +OUTPUT_FORMAT("elf32-powerpc-freebsd", "elf32-powerpc-freebsd", + "elf32-powerpc-freebsd") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +SEARCH_DIR(/usr/lib); +PROVIDE (__stack = 0); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x00010000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.bss : { *(.rela.bss) } + .rela.plt : { *(.rela.plt) } + .rela.sdata : { *(.rela.sdata) } + .rela.sbss : { *(.rela.sbss) } + .rela.sdata2 : { *(.rela.sdata2) } + .rela.sbss2 : { *(.rela.sbss2) } + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + .init : { *(.init) } =0 + .fini : { *(.fini) } =0 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2) } + .sbss2 : { *(.sbss2) } + /* Adjust the address for the data segment to the next page up. */ + . = ((. + 0x1000) & ~(0x1000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .got1 : { *(.got1) } + .dynamic : { *(.dynamic) } + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. + The current compiler no longer needs this, but keep it around for 2.7.2 */ + PROVIDE (_GOT2_START_ = .); + .got2 : { *(.got2) } + PROVIDE (__CTOR_LIST__ = .); + .ctors : { *(.ctors) } + PROVIDE (__CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + .dtors : { *(.dtors) } + PROVIDE (__DTOR_END__ = .); + PROVIDE (_FIXUP_START_ = .); + .fixup : { *(.fixup) } + PROVIDE (_FIXUP_END_ = .); + PROVIDE (_GOT2_END_ = .); + PROVIDE (_GOT_START_ = .); + .got : { *(.got) } + .got.plt : { *(.got.plt) } + PROVIDE (_GOT_END_ = .); + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + .sbss : + { + PROVIDE (__sbss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + PROVIDE (__sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + PROVIDE (__bss_start = .); + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} + diff --git a/stand/powerpc/uboot/start.S b/stand/powerpc/uboot/start.S new file mode 100644 index 000000000000..3e80576907a4 --- /dev/null +++ b/stand/powerpc/uboot/start.S @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <machine/asm.h> + +/* + * Entry point to the loader that U-Boot passes control to. + */ + .text + .globl _start +_start: + /* Hint where to look for the API signature */ + lis %r11, uboot_address@ha + addi %r11, %r11, uboot_address@l + stw %r1, 0(%r11) + /* Save U-Boot's r14 */ + lis %r11, saved_regs@ha + addi %r11, %r11, saved_regs@l + stw %r14, 0(%r11) + /* Disable interrupts */ + mfmsr %r11 + andi. %r11, %r11, ~0x8000@l + mtmsr %r11 + b main + +/* + * syscall() + */ +ENTRY(syscall) + stwu %r1, -16(%r1) + mflr %r0 + stw %r14, 8(%r1) + stw %r0, 20(%r1) + /* Restore U-Boot's r14 */ + lis %r11, saved_regs@ha + addi %r11, %r11, saved_regs@l + lwz %r14, 0(%r11) + /* Enable interrupts */ + mfmsr %r11 + ori %r11, %r11, 0x8000@l + mtmsr %r11 + /* Call into U-Boot */ + lis %r11, syscall_ptr@ha + addi %r11, %r11, syscall_ptr@l + lwz %r11, 0(%r11) + mtctr %r11 + bctrl + /* Disable interrupts */ + mfmsr %r11 + andi. %r11, %r11, ~0x8000@l + mtmsr %r11 + /* Epilogue */ + lwz %r11, 0(%r1) + lwz %r0, 4(%r11) + mtlr %r0 + lwz %r14, 8(%r1) + mr %r1, %r11 + blr + +/* + * Data section + */ + .data +GLOBAL(syscall_ptr) + .long 0 +GLOBAL(saved_regs) + .long 0 /* R14 */ +GLOBAL(uboot_address) + .long 0 diff --git a/stand/powerpc/uboot/version b/stand/powerpc/uboot/version new file mode 100644 index 000000000000..21556cff70e0 --- /dev/null +++ b/stand/powerpc/uboot/version @@ -0,0 +1,11 @@ +$FreeBSD$ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +1.1: Flattened Device Tree blob support. +1.0: Added storage support. +0.6: Integrated with the new U-Boot API +0.5: Full network functionality. +0.2: Initial U-Boot/PowerPC version derived from the existing + OpenFirmware-based. |