summaryrefslogtreecommitdiffstats
path: root/sys/boot/powerpc
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2011-08-14 00:20:37 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2011-08-14 00:20:37 +0000
commitae4052d3f376c0fa7111ebe2cc007fd43435d701 (patch)
treecd0e784c32101b07218ed9cadb5b59ce85cf50f2 /sys/boot/powerpc
parentd7243f9f08159a162ce3b28842403e797017d945 (diff)
downloadFreeBSD-src-ae4052d3f376c0fa7111ebe2cc007fd43435d701.zip
FreeBSD-src-ae4052d3f376c0fa7111ebe2cc007fd43435d701.tar.gz
Add support for the Blu-Ray drive found in the Sony Playstation 3 and fix
some realted minor bugs in PS3 internal storage support. Submitted by: glevand <geoffrey.levand@mail.ru> Approved by: re (bz)
Diffstat (limited to 'sys/boot/powerpc')
-rw-r--r--sys/boot/powerpc/ps3/Makefile3
-rw-r--r--sys/boot/powerpc/ps3/conf.c6
-rw-r--r--sys/boot/powerpc/ps3/devicename.c2
-rw-r--r--sys/boot/powerpc/ps3/lv1call.S10
-rw-r--r--sys/boot/powerpc/ps3/lv1call.h10
-rw-r--r--sys/boot/powerpc/ps3/main.c12
-rw-r--r--sys/boot/powerpc/ps3/ps3cdrom.c154
-rw-r--r--sys/boot/powerpc/ps3/ps3stor.c47
8 files changed, 209 insertions, 35 deletions
diff --git a/sys/boot/powerpc/ps3/Makefile b/sys/boot/powerpc/ps3/Makefile
index 0f0b782..0dee5f4 100644
--- a/sys/boot/powerpc/ps3/Makefile
+++ b/sys/boot/powerpc/ps3/Makefile
@@ -10,7 +10,8 @@ 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
+SRCS+= lv1call.S ps3cons.c font.h ps3mmu.c ps3net.c ps3repo.c \
+ ps3stor.c ps3disk.c ps3cdrom.c
SRCS+= ucmpdi2.c
LOADER_DISK_SUPPORT?= yes
diff --git a/sys/boot/powerpc/ps3/conf.c b/sys/boot/powerpc/ps3/conf.c
index 200fc7f..3a5ae4c 100644
--- a/sys/boot/powerpc/ps3/conf.c
+++ b/sys/boot/powerpc/ps3/conf.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#endif
extern struct devsw ps3disk;
+extern struct devsw ps3cdrom;
/*
* We could use linker sets for some or all of these, but
@@ -47,7 +48,10 @@ extern struct devsw ps3disk;
/* Exported for libstand */
struct devsw *devsw[] = {
-#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT)
+#if defined(LOADER_CD9660_SUPPORT)
+ &ps3cdrom,
+#endif
+#if defined(LOADER_DISK_SUPPORT)
&ps3disk,
#endif
#if defined(LOADER_NET_SUPPORT)
diff --git a/sys/boot/powerpc/ps3/devicename.c b/sys/boot/powerpc/ps3/devicename.c
index c46bc89..041f853 100644
--- a/sys/boot/powerpc/ps3/devicename.c
+++ b/sys/boot/powerpc/ps3/devicename.c
@@ -157,6 +157,7 @@ ps3_parsedev(struct ps3_devdesc **dev, const char *devspec, const char **path)
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
@@ -213,6 +214,7 @@ ps3_fmtdev(void *vdev)
break;
case DEVT_NET:
+ case DEVT_CD:
sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
break;
}
diff --git a/sys/boot/powerpc/ps3/lv1call.S b/sys/boot/powerpc/ps3/lv1call.S
index 1c1e28e..a399a9c 100644
--- a/sys/boot/powerpc/ps3/lv1call.S
+++ b/sys/boot/powerpc/ps3/lv1call.S
@@ -307,14 +307,8 @@ lv1_storage_read:
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
- lwz %r8,16(%r1)
- lwz %r9,20(%r1)
- sldi %r8,%r8,32
- or %r8,%r8,%r9
+ ld %r7,8(%r1)
+ ld %r8,16(%r1)
li %r11,245
hc
diff --git a/sys/boot/powerpc/ps3/lv1call.h b/sys/boot/powerpc/ps3/lv1call.h
index da47afb..fb80448 100644
--- a/sys/boot/powerpc/ps3/lv1call.h
+++ b/sys/boot/powerpc/ps3/lv1call.h
@@ -69,12 +69,12 @@ 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);
+ 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);
+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/sys/boot/powerpc/ps3/main.c b/sys/boot/powerpc/ps3/main.c
index db808ad..64bd7e9 100644
--- a/sys/boot/powerpc/ps3/main.c
+++ b/sys/boot/powerpc/ps3/main.c
@@ -92,11 +92,17 @@ main(void)
}
}
- printf("\nDevice: %s\n", devsw[i]->dv_name);
-
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;
@@ -113,6 +119,8 @@ main(void)
if (devsw[i] == NULL)
panic("No boot device found!");
+ else
+ printf("Boot device: %s\n", devsw[i]->dv_name);
/*
* Get timebase at boot.
diff --git a/sys/boot/powerpc/ps3/ps3cdrom.c b/sys/boot/powerpc/ps3/ps3cdrom.c
new file mode 100644
index 0000000..843ecd5
--- /dev/null
+++ b/sys/boot/powerpc/ps3/ps3cdrom.c
@@ -0,0 +1,154 @@
+/*-
+ * 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 void 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);
+
+ 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 void ps3cdrom_print(int verbose)
+{
+}
diff --git a/sys/boot/powerpc/ps3/ps3stor.c b/sys/boot/powerpc/ps3/ps3stor.c
index 667b39c..bbfc56a 100644
--- a/sys/boot/powerpc/ps3/ps3stor.c
+++ b/sys/boot/powerpc/ps3/ps3stor.c
@@ -52,35 +52,39 @@ int ps3stor_setup(struct ps3_stordev *sd, int type)
if (err)
goto out;
- err = ps3repo_read_bus_dev_id(sd->sd_busidx, sd->sd_devidx, &sd->sd_devid);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ err = ps3repo_read_bus_dev_reg_size(sd->sd_busidx,
+ sd->sd_devidx, i, &sd->sd_regs[i].sr_size);
if (err)
goto out;
}
@@ -109,19 +113,20 @@ 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 4
+#define BOUNCE_SECTORS (sizeof(dma_buf) / sd->sd_blksize)
#define ASYNC_STATUS_POLL_PERIOD 100 /* microseconds */
struct ps3_storreg *reg = &sd->sd_regs[regidx];
- char dma_buf[sd->sd_blksize * BOUNCE_SECTORS];
uint64_t nleft, nread, nsectors;
uint64_t tag, status;
unsigned int timeout;
- int err;
+ int err = 0;
nleft = sector_count;
nread = 0;
@@ -129,8 +134,9 @@ int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx,
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);
+ err = lv1_storage_read(sd->sd_devid, reg->sr_id,
+ start_sector + nread, nsectors, flags, (uint32_t)dma_buf,
+ &tag);
if (err)
return err;
@@ -140,7 +146,8 @@ int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx,
if (timeout < ASYNC_STATUS_POLL_PERIOD)
return ETIMEDOUT;
- err = lv1_storage_check_async_status(sd->sd_devid, tag, &status);
+ err = lv1_storage_check_async_status(sd->sd_devid, tag,
+ &status);
if (!err && !status)
break;
@@ -148,12 +155,16 @@ int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx,
timeout -= ASYNC_STATUS_POLL_PERIOD;
}
- memcpy(buf + nread * sd->sd_blksize, (u_char *) dma_buf, nsectors * sd->sd_blksize);
+ if (status != 0)
+ return EIO;
+
+ memcpy(buf + nread * sd->sd_blksize, (u_char *)dma_buf,
+ nsectors * sd->sd_blksize);
nread += nsectors;
nleft -= nsectors;
}
- return 0;
+ return err;
#undef MIN
#undef BOUNCE_SECTORS
OpenPOWER on IntegriCloud