diff options
author | nwhitehorn <nwhitehorn@FreeBSD.org> | 2011-08-14 00:20:37 +0000 |
---|---|---|
committer | nwhitehorn <nwhitehorn@FreeBSD.org> | 2011-08-14 00:20:37 +0000 |
commit | ae4052d3f376c0fa7111ebe2cc007fd43435d701 (patch) | |
tree | cd0e784c32101b07218ed9cadb5b59ce85cf50f2 /sys/boot | |
parent | d7243f9f08159a162ce3b28842403e797017d945 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/boot/powerpc/ps3/Makefile | 3 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/conf.c | 6 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/devicename.c | 2 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/lv1call.S | 10 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/lv1call.h | 10 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/main.c | 12 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ps3cdrom.c | 154 | ||||
-rw-r--r-- | sys/boot/powerpc/ps3/ps3stor.c | 47 |
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 |