Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable harddisk devices via the expansion bay #18

Open
6 of 8 tasks
frno7 opened this issue Mar 17, 2019 · 30 comments
Open
6 of 8 tasks

Enable harddisk devices via the expansion bay #18

frno7 opened this issue Mar 17, 2019 · 30 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@frno7
Copy link
Owner

frno7 commented Mar 17, 2019

Enable harddisk devices via the PlayStation 2 expansion bay. A starting point is drivers/ata/pata_ps2.c. DMA via the subsystem interface (SIF) is needed for reasonable performance. Plan:

See also #11 and #17.

@frno7 frno7 added enhancement New feature or request help wanted Extra attention is needed labels Mar 17, 2019
frno7 pushed a commit that referenced this issue Apr 19, 2019
[ Upstream commit e5e21f7 ]

Take the regulator lock before applying system load.

Fixes the following lockdep splat:

[    5.583581] WARNING: CPU: 1 PID: 16 at drivers/regulator/core.c:925 drms_uA_update+0x114/0x360
[    5.588467] Modules linked in:
[    5.596833] CPU: 1 PID: 16 Comm: kworker/1:0 Not tainted 5.0.0-rc6-next-20190213-00002-g0fce66ab480f #18
[    5.599933] Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT)
[    5.609544] Workqueue: events qcom_channel_state_worker
[    5.616209] pstate: 60000005 (nZCv daif -PAN -UAO)
[    5.621152] pc : drms_uA_update+0x114/0x360
[    5.626006] lr : drms_uA_update+0x110/0x360
[    5.630084] sp : ffff0000124b3490
[    5.634242] x29: ffff0000124b3490 x28: ffff800005326e00
[    5.637735] x27: ffff0000124b35f8 x26: 000000000032bc48
[    5.643117] x25: ffff800004c7e800 x24: ffff800004c6d500
[    5.648411] x23: ffff800004c38a80 x22: 00000000000000d1
[    5.653706] x21: 00000000001ab3f0 x20: ffff800004c7e800
[    5.659001] x19: ffff0000114c3000 x18: ffffffffffffffff
[    5.664297] x17: 0000000000000000 x16: 0000000000000000
[    5.669592] x15: ffff0000114c3808 x14: 0720072007200720
[    5.674888] x13: 00000000199c9b28 x12: ffff80002bcccc40
[    5.680183] x11: ffff000012286000 x10: ffff0000114c3808
[    5.685477] x9 : 0720072007200720 x8 : ffff000010e9e808
[    5.690772] x7 : ffff0000106da568 x6 : 0000000000000000
[    5.696067] x5 : 0000000000000000 x4 : 0000000000000000
[    5.701362] x3 : 0000000000000004 x2 : 0000000000000000
[    5.706658] x1 : 0000000000000000 x0 : 0000000000000000
[    5.711952] Call trace:
[    5.717223]  drms_uA_update+0x114/0x360
[    5.719405]  regulator_register+0xb30/0x1140
[    5.723230]  devm_regulator_register+0x4c/0xa8
[    5.727745]  rpm_reg_probe+0xfc/0x1b0
[    5.731992]  platform_drv_probe+0x50/0xa0
[    5.735727]  really_probe+0x20c/0x2b8
[    5.739718]  driver_probe_device+0x58/0x100
[    5.743368]  __device_attach_driver+0x90/0xd0
[    5.747363]  bus_for_each_drv+0x64/0xc8
[    5.751870]  __device_attach+0xd8/0x138
[    5.755516]  device_initial_probe+0x10/0x18
[    5.759341]  bus_probe_device+0x98/0xa0
[    5.763502]  device_add+0x3d0/0x640
[    5.767319]  of_device_add+0x48/0x58
[    5.770793]  of_platform_device_create_pdata+0xb0/0x128
[    5.774629]  of_platform_bus_create+0x174/0x370
[    5.779569]  of_platform_populate+0x78/0xe0
[    5.784082]  qcom_smd_rpm_probe+0x80/0xa0
[    5.788245]  rpmsg_dev_probe+0x114/0x1a0
[    5.792411]  really_probe+0x20c/0x2b8
[    5.796401]  driver_probe_device+0x58/0x100
[    5.799964]  __device_attach_driver+0x90/0xd0
[    5.803960]  bus_for_each_drv+0x64/0xc8
[    5.808468]  __device_attach+0xd8/0x138
[    5.812115]  device_initial_probe+0x10/0x18
[    5.815936]  bus_probe_device+0x98/0xa0
[    5.820099]  device_add+0x3d0/0x640
[    5.823916]  device_register+0x1c/0x28
[    5.827391]  rpmsg_register_device+0x4c/0x90
[    5.831216]  qcom_channel_state_worker+0x170/0x298
[    5.835651]  process_one_work+0x294/0x6e8
[    5.840241]  worker_thread+0x40/0x450
[    5.844318]  kthread+0x11c/0x120
[    5.847961]  ret_from_fork+0x10/0x18
[    5.851260] irq event stamp: 9090
[    5.854820] hardirqs last  enabled at (9089): [<ffff000010160798>] console_unlock+0x3e0/0x5b0
[    5.858086] hardirqs last disabled at (9090): [<ffff0000100817cc>] do_debug_exception+0x104/0x140
[    5.866596] softirqs last  enabled at (9086): [<ffff000010082024>] __do_softirq+0x474/0x574
[    5.875446] softirqs last disabled at (9079): [<ffff0000100f2254>] irq_exit+0x13c/0x148
[    5.883598] ---[ end trace 6984ef7f081afa21 ]---

Fixes: fa94e48 ("regulator: core: Apply system load even if no consumer loads")
Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
frno7 pushed a commit that referenced this issue May 20, 2019
…mory

[ Upstream commit a6ecfb1 ]

When halting a guest, QEMU flushes the virtual ITS caches, which
amounts to writing to the various tables that the guest has allocated.

When doing this, we fail to take the srcu lock, and the kernel
shouts loudly if running a lockdep kernel:

[   69.680416] =============================
[   69.680819] WARNING: suspicious RCU usage
[   69.681526] 5.1.0-rc1-00008-g600025238f51-dirty #18 Not tainted
[   69.682096] -----------------------------
[   69.682501] ./include/linux/kvm_host.h:605 suspicious rcu_dereference_check() usage!
[   69.683225]
[   69.683225] other info that might help us debug this:
[   69.683225]
[   69.683975]
[   69.683975] rcu_scheduler_active = 2, debug_locks = 1
[   69.684598] 6 locks held by qemu-system-aar/4097:
[   69.685059]  #0: 0000000034196013 (&kvm->lock){+.+.}, at: vgic_its_set_attr+0x244/0x3a0
[   69.686087]  #1: 00000000f2ed935e (&its->its_lock){+.+.}, at: vgic_its_set_attr+0x250/0x3a0
[   69.686919]  #2: 000000005e71ea54 (&vcpu->mutex){+.+.}, at: lock_all_vcpus+0x64/0xd0
[   69.687698]  #3: 00000000c17e548d (&vcpu->mutex){+.+.}, at: lock_all_vcpus+0x64/0xd0
[   69.688475]  #4: 00000000ba386017 (&vcpu->mutex){+.+.}, at: lock_all_vcpus+0x64/0xd0
[   69.689978]  #5: 00000000c2c3c335 (&vcpu->mutex){+.+.}, at: lock_all_vcpus+0x64/0xd0
[   69.690729]
[   69.690729] stack backtrace:
[   69.691151] CPU: 2 PID: 4097 Comm: qemu-system-aar Not tainted 5.1.0-rc1-00008-g600025238f51-dirty #18
[   69.691984] Hardware name: rockchip evb_rk3399/evb_rk3399, BIOS 2019.04-rc3-00124-g2feec69fb1 03/15/2019
[   69.692831] Call trace:
[   69.694072]  lockdep_rcu_suspicious+0xcc/0x110
[   69.694490]  gfn_to_memslot+0x174/0x190
[   69.694853]  kvm_write_guest+0x50/0xb0
[   69.695209]  vgic_its_save_tables_v0+0x248/0x330
[   69.695639]  vgic_its_set_attr+0x298/0x3a0
[   69.696024]  kvm_device_ioctl_attr+0x9c/0xd8
[   69.696424]  kvm_device_ioctl+0x8c/0xf8
[   69.696788]  do_vfs_ioctl+0xc8/0x960
[   69.697128]  ksys_ioctl+0x8c/0xa0
[   69.697445]  __arm64_sys_ioctl+0x28/0x38
[   69.697817]  el0_svc_common+0xd8/0x138
[   69.698173]  el0_svc_handler+0x38/0x78
[   69.698528]  el0_svc+0x8/0xc

The fix is to obviously take the srcu lock, just like we do on the
read side of things since bf30824. One wonders why this wasn't
fixed at the same time, but hey...

Fixes: bf30824 ("KVM: arm/arm64: VGIC/ITS: protect kvm_read_guest() calls with SRCU lock")
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org>
@motolav
Copy link

motolav commented Sep 14, 2019

I'm waiting on a ABitTop SATA upgrade board and I'd be willing to test out compatibility with it when there's progress with this.

@frno7
Copy link
Owner Author

frno7 commented Sep 14, 2019

Thanks, @motolav! I believe the most complex issue when making a good driver will be efficient use of DMA, especially when sharing DMA with other IOP drivers, for example networking.

@rickgaiser
Copy link

rickgaiser commented Sep 14, 2019

There's already a highly optimized (P)ATA driver for linux v3.8. Fully using linux scatter-gather DMA, and reaching speeds close to the theoretical maximum of UDMA66. The IOP drivers needed can be found here:
https://gitlab.com/ps2max/linux/linux-firmware

It consists of:

  • dev9_dma module for sharing DMA between multiple devices. State: finished
  • pata_ps2 driver for pata. State: finished
  • smaprpc driver for ethernet. State: working, but can be cleaned up and optimized. It uses the MDIO/PHY drivers from linux to setup the physical connections and speeds/duplex.

Also essential for debugging IOP modules, is the eedebug/iopdebug (name is confusing...) driver:
https://gitlab.com/ps2max/linux/linux-firmware/tree/master/eedebug
https://gitlab.com/ps2max/linux/linux/blob/ps2-v3.8/arch/mips/ps2/iopdebug.c
This helps to seend all print/debug messages from the IOP to the EE, so they can then be printed to the default debug output (screen or serial port)

The serial port output is IMO a valabl tool when debugging the kernel. It's been extended to also accept input, so you can start a tty console over serial:
https://gitlab.com/ps2max/linux/linux/blob/ps2-v3.8/drivers/tty/serial/ps2_uart.c

The linux implementation for pata can be found here:
https://gitlab.com/ps2max/linux/linux/blob/ps2-v3.8/drivers/ata/pata_ps2.c

The linux implementation for ethernet can be found here (files: smap*):
https://gitlab.com/ps2max/linux/linux/tree/ps2-v3.8/drivers/ps2

I would like to help out on getting these drivers to work with mailine linux, but I'm not sure if I can get a decent development environment anytime soon since I'm in the middle of moving to another country.

EDIT: For testing I have multiple PATA adapters, a SATA upgraded adapter and a sata clone adapter.

@frno7
Copy link
Owner Author

frno7 commented Sep 14, 2019

Great, @rickgaiser! Your contributions are most welcome. Take your time, we’ll get there.

This helps to seend all print/debug messages from the IOP to the EE, so they can then be printed to the default debug output (screen or serial port)

I have a similar printk IOP module here: https://github.com/frno7/iopmod/blob/master/module/printk.c

The serial port output is IMO a valabl tool when debugging the kernel. It's been extended to also accept input, so you can start a tty console over serial:

I’m unable to test this serial driver myself, since I haven’t soldered a serial port. As an alternative, one can use an early putc with the Graphics Synthesizer, as described in #9. It’s practically equivalent to a true serial port when debugging unmodified hardware, because it will print the same things on the video screen, although it doesn’t accept any input for obvious reasons.

@frno7
Copy link
Owner Author

frno7 commented Dec 16, 2020

@rickgaiser, I have started reviewing your ATA driver and the links you supplied. This will obviously take some time, as there are significant changes between the 3.8 and 5.4 Linux kernels as well as their corresponding IOP module structures. Nevertheless your driver looks like an excellent starting point.

@frno7
Copy link
Owner Author

frno7 commented Jul 10, 2021

@rickgaiser, I get a bus error when reading the ATA registers (from the EE), which I suspect is caused by the DEV9 not being powered on properly. So I have a iop-dev9 module that is supposed to power it on, but it seems something is amiss. It follows the steps of ps2dev9 (expbay_init) of the PS2SDK. And not entirely wrong either, I assume, because it properly detects the expansion device by printing dev9: Expansion device interface during initialisation. It also claims that the DEV9 is already powered on, by printing dev9: Expansion device already powered on, which might be wrong, because reading the registers corresponding to SPD_R_REV_1 and SPD_R_REV_3 in the PS2SDK, for example, give bus errors too.

Any ideas on what might be wrong?

There’s quite a bit of obscure hardware poking going on, as can be seen, during expansion device initialisation:

static int __init exp_dev_init(void)
{
bool power;
int err;
err = iop_ssbus_write_1420(0x51011);
if (err < 0)
return err;
err = iop_ssbus_write_1418(0xe01a3043);
if (err < 0)
return err;
err = iop_ssbus_write_141c(0xef1a3043);
if (err < 0)
return err;
err = iop_dev9_power(&power);
if (err < 0)
return err;
if (!power)
{
u16 reg_1464;
printk("dev9: Expansion device power on\n"); /* FIXME */
err = iop_dev9_write_1466(1);
if (err < 0)
return err;
err = iop_dev9_write_1464(0);
if (err < 0)
return err;
err = iop_dev9_read_1464(&reg_1464);
if (err < 0)
return err;
err = iop_dev9_write_1460(reg_1464);
if (err < 0)
return err;
err = exp_dev_reset();
if (err < 0)
return err;
} else {
printk("dev9: Expansion device already powered on\n"); /* FIXME */
}
#if 0
err = iop_dev9_write_1464(0x103 & 0x3f); /* ??? */
if (err < 0)
return err;
#endif
err = iop_dev9_write_1466(0);
if (err < 0)
return err;
iop_set_dma_dpcr2(IOP_DMA_DPCR2_DEV9);
return 0;
}

@frno7
Copy link
Owner Author

frno7 commented Jul 10, 2021

I wrote a minimal dev9 IOP module replacement, and then the initialisation works. It prints

iop: dev9: init start
iop: dev9: rev 31
iop: dev9: power is already on
iop: dev9: spdrev 11
iop: dev9: init exit

in the kernel log, as one would hope for. And then the ATA driver proceeds with

scsi host1: pata-ps2
ata1: PATA max PIO3 irq 77
ata1.00: qc timeout (cmd 0x27)
ata1.00: failed to read native max address (err_mask=0x4)
ata1.00: HPA support seems broken, skipping HPA handling
ata1.00: ATA-11: KINGSTON SA400S37120G, SBFK71E0, max UDMA/133
ata1.00: 234441648 sectors, multi 16: LBA48 
scsi 1:0:0:0: Direct-Access     ATA      KINGSTON SA400S3 71E0 PQ: 0 ANSI: 5
sd 1:0:0:0: [sdb] 234441648 512-byte logical blocks: (120 GB/112 GiB)
sd 1:0:0:0: [sdb] Write Protect is off
sd 1:0:0:0: [sdb] Mode Sense: 00 3a 00 00
sd 1:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA

which is to be expected, at the moment, because it’s not fully implemented. Although I started out on the EE, it probably is best to do most things on the IOP instead, since it can offload a lot of work for the benefit of the EE. Interesting things can be done if IOP would stream all data through the SIF.

@frno7
Copy link
Owner Author

frno7 commented Jul 11, 2021

It’s easy to get the driver to work with polling, that is without interrtupts, by ap->flags |= ATA_FLAG_PIO_POLLING:

ata1: PATA max PIO3 irq 77
ata1.00: ATA-11: KINGSTON SA400S37120G, SBFK71E0, max UDMA/133
ata1.00: 234441648 sectors, multi 16: LBA48 
scsi 1:0:0:0: Direct-Access     ATA      KINGSTON SA400S3 71E0 PQ: 0 ANSI: 5
sd 1:0:0:0: [sdb] 234441648 512-byte logical blocks: (120 GB/112 GiB)
sd 1:0:0:0: [sdb] Write Protect is off
sd 1:0:0:0: [sdb] Mode Sense: 00 3a 00 00
sd 1:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
 sdb: sdb1 sdb2
sd 1:0:0:0: [sdb] Attached SCSI disk

I’ve prepared two partitions that are now detected properly:

# fdisk -l /dev/sdb
Disk /dev/sdb: 112 GB, 120034123776 bytes, 234441648 sectors
14593 cylinders, 255 heads, 63 sectors/track
Units: cylinders of 16065 * 512 = 8225280 bytes

Device  Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/sdb1    0,0,2       124,254,63           1    2008124    2008124  980M 82 Linux swap
/dev/sdb2    125,0,1     256,254,63     2008125  234436544  232428420  110G 83 Linux

Mounting an EXT4 file system works too:

# mount /dev/sdb2 /mnt
# ls /mnt
lost+found

Of course, with its polling mode, it’s very slow at the moment, as seen with the dd command:

# dd if=/dev/sdb of=/dev/null bs=4096 count=4096
4096+0 records in
4096+0 records out
16777216 bytes (16.0MB) copied, 9.129766 seconds, 1.8MB/s

@rickgaiser mentioned UDMA/66, which is more than 30× faster than this. The device itself advertises UDMA/133, as shown above. The next task is to get interrupts working. Somehow the registered IRQ_IOP_DEV9 isn’t asserted. Perhaps some part of the DEV9 hardware isn’t enabled, or some special quirk is needed somewhere?

@AKuHAK
Copy link

AKuHAK commented Jul 11, 2021

A little offtop:
@frno7 just want to mention, that if you want to get a fast answer for some specific question, you can enjoy the discord channel. Almost all active developers are there.

@rickgaiser
Copy link

@rickgaiser, I get a bus error when reading the ATA registers (from the EE)

Although I started out on the EE, it probably is best to do most things on the IOP instead, since it can offload a lot of work for the benefit of the EE. Interesting things can be done if IOP would stream all data through the SIF.

The EE can access many things on the IOP bus (memory/devices), but these accesses are always much slower than doing things on the IOP, and transferring the data using DMA. I'm not sure what you mean by "stream all data through the SIF", but it's impossible to stream data directly from HDD -> EE. It always involves 2 DMA transfers (HDD -> IOP -> EE).

@rickgaiser mentioned UDMA/66, which is more than 30× faster than this. The device itself advertises UDMA/133, as shown above. The next task is to get interrupts working. Somehow the registered IRQ_IOP_DEV9 isn’t asserted. Perhaps some part of the DEV9 hardware isn’t enabled, or some special quirk is needed somewhere?

All needed quirks should be in here:
https://github.com/ps2dev/ps2sdk/blob/master/iop/dev9/dev9/src/ps2dev9.c

About the speed, there's a few things to note:

  • The old ATA protocol is not very efficient. UDMA66 will never be able to reach 66MB/s, not even on a modern PC. More like 40 to 50MB/s.
  • The fastest route to get data from HDD to the EE is 2x DMA transfers. The first from HDD -> IOP. The second from IOP -> EE. Since both transfers use the IOP memory, that will become a bottleneck. With the IOP memory bandwith a little over 100MB/s, the theoretical max speed is half of that.

To gain max speed:

  • both DMA transfers have to be active at the same time.
  • scatter-gather lists from linux have to be sent to the IOP. The IOP can transfer the data directly to the correct memory location on the EE.

That being said, 40+ MB/s has been proven possible on ps2/linux.

@frno7
Copy link
Owner Author

frno7 commented Jul 12, 2021

I'm not sure what you mean by "stream all data through the SIF", but it's impossible to stream data directly from HDD -> EE. It always involves 2 DMA transfers (HDD -> IOP -> EE).

That’s what I had in mind. The SIF can exchange data with several devices too, such as the image processing unit (IPU) in #15 etc. and so isn’t limited to memory transfers only. In principle, I suppose one could make a command such as cat somefile >/dev/ipu do all data copying in hardware. That could be interesting.

Incidentally, would you happen to know the details on how to acknowledge interrupts with DEV9 (see frno7/iopmod#5), more specifically the ones for SPD_REG16(SPD_R_INTR_STAT) and SPD_REG16(SPD_R_INTR_MASK)? I would expect that to be done somewhere near dev9_intr_dispatch in the PS2SDK, but I couldn’t find it.

Related to frno7/iopmod#5 is also finding documentation on the following DEV9 registers, if someone has figured them out and invented better names for them:

enum _dev9_regnames {
       DEV9_R_1460, DEV9_R_1462, DEV9_R_1464, DEV9_R_1466, DEV9_R_1468,
       DEV9_R_146A, DEV9_R_POWER,DEV9_R_REV,  DEV9_R_1470, DEV9_R_1472,
       DEV9_R_1474, DEV9_R_1476, DEV9_R_1478, DEV9_R_147A, DEV9_R_147C,
       DEV9_R_147E,
       DEV9_R_MAX };

@rickgaiser
Copy link

Incidentally, would you happen to know the details on how to acknowledge interrupts with DEV9 (see frno7/iopmod#5), more specifically the ones for SPD_REG16(SPD_R_INTR_STAT) and SPD_REG16(SPD_R_INTR_MASK)? I would expect that to be done somewhere near dev9_intr_dispatch in the PS2SDK, but I couldn’t find it.

Perhaps you're looking for SMAP_REG16(SMAP_R_INTR_CLR), as in this example:
https://github.com/ps2dev/ps2sdk/blob/dd9b0b734b1cabf7342c5e2d9278967024745922/iop/network/smap/src/smap.c#L445
I'm not sure why the one is named "SMAP" and the other "SPD", but it seems to use the same flags for both registers in the link above.

@frno7
Copy link
Owner Author

frno7 commented Jul 12, 2021

Yes, thanks, I’ll try that! With cascading interrupts for DEV9, I believe some parts of the ATA driver can be simplified, and perhaps even more so the SMAP driver. The IRQ relay module will work automatically with DEV9 IRQs too, and so on.

@AKuHAK
Copy link

AKuHAK commented Jul 12, 2021

As about dev9 register references - I found only this, this and this.

@frno7
Copy link
Owner Author

frno7 commented Jul 12, 2021

@AKuHAK, the first link seems broken, no?

@frno7
Copy link
Owner Author

frno7 commented Jul 12, 2021

Interrupts are now working with the ATA driver, via a new IRQ_IOP_SPD_ATA0 virtual IRQ relay, as explained in frno7/iopmod#5 (comment). Data transfer performance isn’t any better for it, at the moment, but it’s nevertheless a prerequisite for DMA that is expected to be a major improvement.

@frno7
Copy link
Owner Author

frno7 commented Jul 14, 2021

Now reading via DMA works, as a proof of concept, with a useful 31 MB/s:

# dd if=/dev/sda of=/dev/null bs=4096 count=4096
4096+0 records in
4096+0 records out
16777216 bytes (16.0MB) copied, 0.513587 seconds, 31.2MB/s

That’s a 17× improvement over polling. Verifying file checksums on a mounted file system etc. works too. Before implementing writing via DMA, I’m going to refactor the driver. Redesign it entirely, in fact, to make better use of resources. This harddisk driver will eventually need to work concurrently and share resources with the network driver described in #19, for example.

@uyjulian
Copy link

It is possible to place APA and GPT on the same hard disk, so you could e.g. boot Linux from the hard disk (possibly with a kernel bootstrapper as __mbr (not to be confused with MBR partitioning scheme)) and use e.g. ext4 on that same hard disk. https://www.psx-place.com/threads/apa-jail.34847/

@frno7
Copy link
Owner Author

frno7 commented Aug 14, 2021

@uyjulian, I’m unfamiliar with APA, but the general steps for Linux 5.x are these:

  1. a boot loader such as wLaunchELF starts a compressed ELF image of a Linux 5.x kernel, from any medium that the boot loader can manage;
  2. the INITRAMFS embedded in the compressed Linux 5.x kernel ELF configures the necessary devices and starts any custom init scripts, and so on;
  3. optional file systems are mounted etc. and the root_pivot command is performed to switch the root from the RAM disk to some other mounted file system, whatever that is;
  4. the INITRAMFS can be unmounted and discarded, to reuse its memory for more useful things.

If the Linux kernel doesn’t understand APA, then this could of course, in principle, be implemented. I did some searching and found that someone has written a guide for APA partition support that claims that for Linux 2.x this allows your PS2 Linux and PS2 Game Data to co-exist on the same hard-drive. Linux 5.x may need some additional adaptions, though.

In short, yes, it should be possible with a bit of work.

@AKuHAK
Copy link

AKuHAK commented Aug 14, 2021

This hybrid scheme will allow to not use APA at all. The only thing, in such a case primary GPT partition header should be in sector 2, not in sector 1, first 2 sectors will be filled with customized APA mbr, and partitions should start at specific offsets. This approach differs from link that you posted, cause there is firstly mounted APA partition, but with customized hybrid scheme you can skip APA step completely.

@frno7
Copy link
Owner Author

frno7 commented Aug 15, 2021

@AKuHAK, thanks for the clarification. I’ve created #39 for the APA.

@frno7
Copy link
Owner Author

frno7 commented Dec 31, 2022

modprobe pata_ps2 will now enable reading harddisks, including mounting compatible preexisting filesystems via mount -o ro /dev/sda1 /mnt or suchlike. Something like dd if=/dev/sda of=/dev/null bs=4096 count=4096 can be used to test reading speeds.

Commits frno7/iopmod@5ccf9d9 and frno7/iopmod@5ccf9d9 have the corresponding DEV9 and ATA modules for the IOP. As usual, the IRX modules are compiled, installed and linked automatically on a properly updated and configured system.

Unfortunately, I’ve not yet been able to complete the refactoring, due to an apparent hardware timing issue. The DEV9 hardware appears to crash with the changes I was planning to do. Maybe something becomes slightly wrong with the interaction between the ATA and the DEV9 DMA registers? DEV9 triggers bus errors when attempting to access its registers. I won’t attempt to enable writing harddisks until this is solved.

A bounce buffer now handles all cases of unaligned transfers properly. Reading speed is currently about 20 MB/s with the particular hardware I have. At least 30 MB/s can be done with some tuning. Maybe even more than 40 MB/s with some effort.

@uyjulian
Copy link

One thing I noticed is that you are missing the delays when powering on dev9. If those delays are missing, they could be possibly causing a bus error.

Another possibility is the connection between the PS2 and the network adapter is not very good, which may also cause bus errors.

If the code is based on a Linux kernel that needs to be booted from kernelloader or RTE, it may be possible that dev9 was already powered on beforehand, so that code path was not tested very much.

@frno7
Copy link
Owner Author

frno7 commented Jan 1, 2023

One thing I noticed is that you are missing the delays when powering on dev9. If those delays are missing, they could be possibly causing a bus error.

Hmm. Yeah, but the pata_ps2 driver on the ps2-main branch actually does work with the current delayless DEV9 power on sequence. It’s stable without issues after hours of testing. :-)

Another possibility is the connection between the PS2 and the network adapter is not very good, which may also cause bus errors.

I suspect it’s an ATA module (iopmod:module/ata.c) software problem with the IOP, at least until I learn more details. The driver is fine when DEV9 DMA is serviced in its ata_sif_cmd_sg SIF command interrupt. However, I should like it to use a separate IOP thread, by waking it up with thsemap_isignal_sema(dev->sg_sema_id), rather than calling ata_sif_cmd_sg_transfer directly during the interrupt:

#if 0
	/* Waking up the thread to do DEV9 DMA crashes the DEV9 hardware. Timing problem? */
	thsemap_isignal_sema(dev->sg_sema_id);
#else
	/* Servicing DEV9 DMA directly in the SIF command interrupt is fine. */
	ata_sif_cmd_sg_transfer(dev);
#endif

Servicing DEV9 DMA requests in a separate IOP thread changes the timing, which I suspect is the issue with the IOP thread:

	for (;;) {
		thsemap_wait_sema(dev->sg_sema_id);

		ata_sif_cmd_sg_transfer(dev);
	}

If the code is based on a Linux kernel that needs to be booted from kernelloader or RTE, it may be possible that dev9 was already powered on beforehand, so that code path was not tested very much.

Yeah, the IOP DEV9 module iopmod:module/dev9.c isn’t exactly tidy, mostly because it’s a pile of magic numbers for undocumented DEV9 registers. dev9_power_off isn’t even implemented properly. Hopefully, all these registers and their bit fields can be given names and meanings, eventually.

@uyjulian
Copy link

uyjulian commented Mar 12, 2023

For booting off HDD, you actually don't need to worry about APA. You can just stick with MBR or GPT while performing minimal modifications to sector 0.

In order to do hdd boot, only sector 0 (same as MBR) and the sector size/offset specified in sector 0 (can create a GPT partition to store this data) needs to be modified (which specifies the location and size of the program to be loaded).
In sector 0, it only cares about bytes 304-312. That is where the offset and size (4 byte integer each, in sectors) are stored
Normally, in MBR, that would be inside the bootstrap code part 2 location
https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout
SoftDev2 is one such program that can be specified in that sector size/offset: https://github.com/parrado/SoftDev2

So it should be possible to make a disk that is bootable in both PC(BIOS+UEFI) and PS2. (But there isn't much of a use case for that.)

@frno7
Copy link
Owner Author

frno7 commented Mar 12, 2023

I assume some people will use the fdisk command that comes with the precompiled Busybox, see frno7/gentoo-mipsr5900el#5 (comment), so everything about partitioning and formatting disks can be done on the PlayStation 2. That’s how I prepared its hard disk, anyway. Is this boot tied to having wLaunchELF?

@uyjulian
Copy link

uyjulian commented Mar 12, 2023

wLaunchELF is not required. The Linux chainloader or the Linux kernel itself can be stored on the specified sector size/offset.

However, the following restrictions reply:

  1. The binary must be a raw binary to be loaded at 0x00100000 (-O binary argument of objcopy), wrapped in a KELF container. SoftDev2 has a sample of this
  2. The binary must fit in the IOP memory. It won't be streamed into the EE (so basically this makes the size limit less than 1MB)
    So if the Linux kernel can't fit in less than 1MB, a chainloader is needed (just like BIOS needs it to fit in the MBR)

@frno7
Copy link
Owner Author

frno7 commented Mar 13, 2023

Ah, is standard Sony BIOS able to boot programs from hard disks?

@uyjulian
Copy link

Ah, is standard Sony BIOS able to boot programs from hard disks?

Only from SCPH-3xxxxx to SCPH-5xxxxx.

@frno7
Copy link
Owner Author

frno7 commented Mar 14, 2023

Ah, is standard Sony BIOS able to boot programs from hard disks?

Only from SCPH-3xxxxx to SCPH-5xxxxx.

Oh, this is very nice and something I think we should most definitely make good use of. :-)

@frno7 frno7 mentioned this issue Jun 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

5 participants