diff options
Diffstat (limited to 'sys/boot/powerpc')
-rw-r--r-- | sys/boot/powerpc/Makefile | 2 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/Makefile | 122 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/conf.c | 119 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/devicename.c | 238 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/help.ps3 | 1 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ldscript.powerpc | 112 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/lv1call.S | 256 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/lv1call.h | 72 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/main.c | 211 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/metadata.c | 355 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ppc64_elf_freebsd.c | 98 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ps3.h | 35 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ps3cons.c | 173 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ps3mmu.c | 120 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ps3net.c | 278 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/start.S | 167 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/version | 6 |
17 files changed, 2364 insertions, 1 deletions
diff --git a/sys/boot/powerpc/Makefile b/sys/boot/powerpc/Makefile index 80a68a6..d3652c4 100644 --- a/sys/boot/powerpc/Makefile +++ b/sys/boot/powerpc/Makefile @@ -1,5 +1,5 @@ # $FreeBSD$ -SUBDIR= boot1.chrp ofw uboot +SUBDIR= boot1.chrp ofw ps3 uboot .include <bsd.subdir.mk> diff --git a/sys/boot/powerpc/ps3/Makefile b/sys/boot/powerpc/ps3/Makefile new file mode 100644 index 0000000..b3a37be --- /dev/null +++ b/sys/boot/powerpc/ps3/Makefile @@ -0,0 +1,122 @@ +# $FreeBSD$ + +.include <bsd.own.mk> +MK_SSP= no + +PROG= loader.ps3 +NEWVERSWHAT= "Playstation 3 loader" ${MACHINE_ARCH} +BINDIR?= /boot +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 +SRCS+= ucmpdi2.c + +LOADER_DISK_SUPPORT?= yes +LOADER_UFS_SUPPORT?= yes +LOADER_CD9660_SUPPORT?= yes +LOADER_EXT2FS_SUPPORT?= no +LOADER_NET_SUPPORT?= yes +LOADER_NFS_SUPPORT?= yes +LOADER_TFTP_SUPPORT?= no +LOADER_GZIP_SUPPORT?= yes +LOADER_FDT_SUPPORT?= no +LOADER_BZIP2_SUPPORT?= no + +.if ${LOADER_DISK_SUPPORT} == "yes" +CFLAGS+= -DLOADER_DISK_SUPPORT +.endif +.if ${LOADER_UFS_SUPPORT} == "yes" +CFLAGS+= -DLOADER_UFS_SUPPORT +.endif +.if ${LOADER_CD9660_SUPPORT} == "yes" +CFLAGS+= -DLOADER_CD9660_SUPPORT +.endif +.if ${LOADER_EXT2FS_SUPPORT} == "yes" +CFLAGS+= -DLOADER_EXT2FS_SUPPORT +.endif +.if ${LOADER_GZIP_SUPPORT} == "yes" +CFLAGS+= -DLOADER_GZIP_SUPPORT +.endif +.if ${LOADER_BZIP2_SUPPORT} == "yes" +CFLAGS+= -DLOADER_BZIP2_SUPPORT +.endif +.if ${LOADER_NET_SUPPORT} == "yes" +CFLAGS+= -DLOADER_NET_SUPPORT +.endif +.if ${LOADER_NFS_SUPPORT} == "yes" +CFLAGS+= -DLOADER_NFS_SUPPORT +.endif +.if ${LOADER_TFTP_SUPPORT} == "yes" +CFLAGS+= -DLOADER_TFTP_SUPPORT +.endif +.if ${LOADER_FDT_SUPPORT} == "yes" +CFLAGS+= -I${.CURDIR}/../../fdt +CFLAGS+= -I${.OBJDIR}/../../fdt +CFLAGS+= -DLOADER_FDT_SUPPORT +LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a +.endif + + +.if ${MK_FORTH} != "no" +# Enable BootForth +BOOT_FORTH= yes +CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/powerpc +LIBFICL= ${.OBJDIR}/../../ficl/libficl.a +.endif + +# Avoid the open-close-dance for every file access as some firmwares perform +# an auto-negotiation on every open of the network interface and thus causes +# netbooting to take horribly long. +CFLAGS+= -DNETIF_OPEN_CLOSE_ONCE -mcpu=powerpc64 + +# Always add MI sources +.PATH: ${.CURDIR}/../../common ${.CURDIR}/../../../libkern +.include "${.CURDIR}/../../common/Makefile.inc" +CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. +CFLAGS+= -I. + +CLEANFILES+= vers.c loader.help + +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 + +# Pull in common loader code +#.PATH: ${.CURDIR}/../../ofw/common +#.include "${.CURDIR}/../../ofw/common/Makefile.inc" + +# where to get libstand from +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ + +DPADD= ${LIBFICL} ${LIBOFW} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBOFW} -lstand + +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 + +vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version + sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} + +loader.help: help.common help.ps3 + cat ${.ALLSRC} | \ + awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} + +.PATH: ${.CURDIR}/../../forth +FILES= loader.help loader.4th support.4th loader.conf +FILESDIR_loader.conf= /boot/defaults + +.if !exists(${DESTDIR}/boot/loader.rc) +FILES+= loader.rc +.endif + +.include <bsd.prog.mk> diff --git a/sys/boot/powerpc/ps3/conf.c b/sys/boot/powerpc/ps3/conf.c new file mode 100644 index 0000000..7749a15 --- /dev/null +++ b/sys/boot/powerpc/ps3/conf.c @@ -0,0 +1,119 @@ +/*- + * 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 + +/* + * 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) +#ifdef NOTYET + &ps3disk, +#endif +#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/sys/boot/powerpc/ps3/devicename.c b/sys/boot/powerpc/ps3/devicename.c new file mode 100644 index 0000000..b652d9b --- /dev/null +++ b/sys/boot/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" + +static int ps3_parsedev(struct 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 devdesc **dev = (struct 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 devdesc **dev, const char *devspec, const char **path) +{ + struct 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 devdesc)); + err = 0; + np = (devspec + strlen(dv->dv_name)); + + switch(dv->dv_type) { + case DEVT_NONE: + break; + +#ifdef NOTYET + 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; +#endif + + case DEVT_NET: + /* + * 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 devdesc *dev = (struct devdesc *)vdev; + char *cp; + static char buf[128]; + + switch(dev->d_type) { + case DEVT_NONE: + strcpy(buf, "(no device)"); + break; + +#ifdef NOTYET + 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; +#endif + + case DEVT_NET: + 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 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/sys/boot/powerpc/ps3/help.ps3 b/sys/boot/powerpc/ps3/help.ps3 new file mode 100644 index 0000000..5873eb0 --- /dev/null +++ b/sys/boot/powerpc/ps3/help.ps3 @@ -0,0 +1 @@ +$FreeBSD$ diff --git a/sys/boot/powerpc/ps3/ldscript.powerpc b/sys/boot/powerpc/ps3/ldscript.powerpc new file mode 100644 index 0000000..3400a85 --- /dev/null +++ b/sys/boot/powerpc/ps3/ldscript.powerpc @@ -0,0 +1,112 @@ +/* $FreeBSD$ */ + +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc:common) +ENTRY(_start) +SEARCH_DIR(/usr/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +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/sys/boot/powerpc/ps3/lv1call.S b/sys/boot/powerpc/ps3/lv1call.S new file mode 100644 index 0000000..a5dafdd --- /dev/null +++ b/sys/boot/powerpc/ps3/lv1call.S @@ -0,0 +1,256 @@ +/*- + * 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$ + */ + +/* 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 + ori %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 + diff --git a/sys/boot/powerpc/ps3/lv1call.h b/sys/boot/powerpc/ps3/lv1call.h new file mode 100644 index 0000000..26e6e14 --- /dev/null +++ b/sys/boot/powerpc/ps3/lv1call.h @@ -0,0 +1,72 @@ +/*- + * 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); + +#endif + diff --git a/sys/boot/powerpc/ps3/main.c b/sys/boot/powerpc/ps3/main.c new file mode 100644 index 0000000..22c51fa --- /dev/null +++ b/sys/boot/powerpc/ps3/main.c @@ -0,0 +1,211 @@ +/*- + * 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 <sys/param.h> + +#define _KERNEL +#include <machine/cpufunc.h> + +#include "bootstrap.h" +#include "lv1call.h" +#include "ps3.h" + +struct arch_switch archsw; +extern void *_end; + +extern char bootprog_name[]; +extern char bootprog_rev[]; +extern char bootprog_date[]; +extern char bootprog_maker[]; + +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; + + 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) + (devsw[i]->dv_init)(); + + /* + * 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"); + printf("%s, Revision %s\n", bootprog_name, bootprog_rev); + printf("(%s, %s)\n", bootprog_maker, bootprog_date); + printf("Memory: %lldKB\n", maxmem / 1024); + + env_setenv("currdev", EV_VOLATILE, "net", ps3_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, "net", env_noset, env_nounset); + setenv("LINES", "24", 1); + setenv("hw.platform", "ps3", 1); + + interact(); /* 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 + (usecs * 1000 + ns_per_tick - 1) / ns_per_tick; + while (tb < ttb) + tb = mftb(); +} + +int +getsecs() +{ + return ((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/sys/boot/powerpc/ps3/metadata.c b/sys/boot/powerpc/ps3/metadata.c new file mode 100644 index 0000000..0698cd1 --- /dev/null +++ b/sys/boot/powerpc/ps3/metadata.c @@ -0,0 +1,355 @@ +/*- + * 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 <machine/metadata.h> + +#include "bootstrap.h" + +/* + * Return a 'boothowto' value corresponding to the kernel arguments in + * (kargs) and any relevant environment variables. + */ +static struct +{ + const char *ev; + int mask; +} howto_names[] = { + {"boot_askname", RB_ASKNAME}, + {"boot_cdrom", RB_CDROM}, + {"boot_ddb", RB_KDB}, + {"boot_dfltroot", RB_DFLTROOT}, + {"boot_gdb", RB_GDB}, + {"boot_multicons", RB_MULTIPLE}, + {"boot_mute", RB_MUTE}, + {"boot_pause", RB_PAUSE}, + {"boot_serial", RB_SERIAL}, + {"boot_single", RB_SINGLE}, + {"boot_verbose", RB_VERBOSE}, + {NULL, 0} +}; + +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/sys/boot/powerpc/ps3/ppc64_elf_freebsd.c b/sys/boot/powerpc/ps3/ppc64_elf_freebsd.c new file mode 100644 index 0000000..2892448 --- /dev/null +++ b/sys/boot/powerpc/ps3/ppc64_elf_freebsd.c @@ -0,0 +1,98 @@ +/*- + * 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 */ + 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/sys/boot/powerpc/ps3/ps3.h b/sys/boot/powerpc/ps3/ps3.h new file mode 100644 index 0000000..1a77002 --- /dev/null +++ b/sys/boot/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/sys/boot/powerpc/ps3/ps3cons.c b/sys/boot/powerpc/ps3/ps3cons.c new file mode 100644 index 0000000..fa9ef32 --- /dev/null +++ b/sys/boot/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/sys/boot/powerpc/ps3/ps3mmu.c b/sys/boot/powerpc/ps3/ps3mmu.c new file mode 100644 index 0000000..a7005fb --- /dev/null +++ b/sys/boot/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(mfmsr() | PSL_IR | PSL_DR | PSL_RI | PSL_ME); + + return (0); +} + diff --git a/sys/boot/powerpc/ps3/ps3net.c b/sys/boot/powerpc/ps3/ps3net.c new file mode 100644 index 0000000..142eab8 --- /dev/null +++ b/sys/boot/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/sys/boot/powerpc/ps3/start.S b/sys/boot/powerpc/ps3/start.S new file mode 100644 index 0000000..92b02f0 --- /dev/null +++ b/sys/boot/powerpc/ps3/start.S @@ -0,0 +1,167 @@ +/*- + * 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$ + */ + +#include <machine/trap_aim.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/sys/boot/powerpc/ps3/version b/sys/boot/powerpc/ps3/version new file mode 100644 index 0000000..fa0b185 --- /dev/null +++ b/sys/boot/powerpc/ps3/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 PS3/PowerPC version. |