From 441713d959bb24aedd948ad1779ece5ea2fc67f5 Mon Sep 17 00:00:00 2001 From: clienthax Date: Sat, 17 Jul 2021 21:06:40 +0100 Subject: [PATCH] sys_storage vsh implementation (#10559) Co-authored-by: Eladash --- rpcs3/Emu/Cell/lv2/sys_storage.cpp | 298 ++++++++++++++++++++++++++++- rpcs3/Emu/Cell/lv2/sys_storage.h | 41 ++++ 2 files changed, 336 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_storage.cpp b/rpcs3/Emu/Cell/lv2/sys_storage.cpp index fbc6de4c15..6418d7c8aa 100644 --- a/rpcs3/Emu/Cell/lv2/sys_storage.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_storage.cpp @@ -1,23 +1,56 @@ #include "stdafx.h" +#include "Emu/Memory/vm.h" +#include "Emu/IdManager.h" #include "Emu/Cell/ErrorCodes.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "util/shared_ptr.hpp" #include "sys_storage.h" - LOG_CHANNEL(sys_storage); +namespace +{ + struct storage_manager + { + // This is probably wrong and should be assigned per fd or something + atomic_ptr> asyncequeue; + }; +} + error_code sys_storage_open(u64 device, u64 mode, vm::ptr fd, u64 flags) { sys_storage.todo("sys_storage_open(device=0x%x, mode=0x%x, fd=*0x%x, flags=0x%x)", device, mode, fd, flags); - return CELL_OK; + if (device == 0) + { + return CELL_ENOENT; + } + + if (!fd) + { + return CELL_EFAULT; + } + + u64 storage_id = device & 0xFFFFF00FFFFFFFF; + fs::file file; + + if (const u32 id = idm::make(device, std::move(file), mode, flags)) + { + *fd = id; + return CELL_OK; + } + + return CELL_EAGAIN; } error_code sys_storage_close(u32 fd) { sys_storage.todo("sys_storage_close(fd=0x%x)", fd); + idm::remove(fd); + return CELL_OK; } @@ -25,6 +58,33 @@ error_code sys_storage_read(u32 fd, u32 mode, u32 start_sector, u32 num_sectors, { sys_storage.todo("sys_storage_read(fd=0x%x, mode=0x%x, start_sector=0x%x, num_sectors=0x%x, bounce_buf=*0x%x, sectors_read=*0x%x, flags=0x%x)", fd, mode, start_sector, num_sectors, bounce_buf, sectors_read, flags); + if (!bounce_buf || !sectors_read) + { + return CELL_EFAULT; + } + + memset(bounce_buf.get_ptr(), 0, num_sectors * 0x200); + + auto handle = idm::get(fd); + if (!handle) + { + return CELL_ESRCH; // idk + } + + if (handle->device_id == 0x100000200000004 && handle->file) + { + handle->file.seek(start_sector * 0x200); + u64 size = num_sectors * 0x200; + const u64 result = handle->file.read(bounce_buf.get_ptr(), size); + + if (result != size) // mjau + { + fmt::throw_exception("didnt read expected"); + } + } + + *sectors_read = num_sectors; + return CELL_OK; } @@ -32,6 +92,13 @@ error_code sys_storage_write(u32 fd, u32 mode, u32 start_sector, u32 num_sectors { sys_storage.todo("sys_storage_write(fd=0x%x, mode=0x%x, start_sector=0x%x, num_sectors=0x%x, data=*=0x%x, sectors_wrote=*0x%x, flags=0x%llx)", fd, mode, start_sector, num_sectors, data, sectors_wrote, flags); + if (!sectors_wrote) + { + return CELL_EFAULT; + } + + *sectors_wrote = num_sectors; + return CELL_OK; } @@ -46,6 +113,17 @@ error_code sys_storage_async_configure(u32 fd, u32 io_buf, u32 equeue_id, u32 un { sys_storage.todo("sys_storage_async_configure(fd=0x%x, io_buf=0x%x, equeue_id=0x%x, unk=*0x%x)", fd, io_buf, equeue_id, unk); + auto& manager = g_fxo->get(); + + if (auto queue = idm::get(equeue_id)) + { + manager.asyncequeue.store(queue); + } + else + { + return CELL_ESRCH; + } + return CELL_OK; } @@ -53,6 +131,13 @@ error_code sys_storage_async_send_device_command(u32 dev_handle, u64 cmd, vm::pt { sys_storage.todo("sys_storage_async_send_device_command(dev_handle=0x%x, cmd=0x%llx, in=*0x%x, inlen=0x%x, out=*0x%x, outlen=0x%x, unk=0x%x)", dev_handle, cmd, in, inlen, out, outlen, unk); + auto& manager = g_fxo->get(); + + if (auto q = *manager.asyncequeue.load()) + { + q->send(0, unk, unk, unk); + } + return CELL_OK; } @@ -81,6 +166,168 @@ error_code sys_storage_get_device_info(u64 device, vm::ptr bu { sys_storage.todo("sys_storage_get_device_info(device=0x%x, buffer=*0x%x)", device, buffer); + if (!buffer) + { + return CELL_EFAULT; + } + + memset(buffer.get_ptr(), 0, sizeof(StorageDeviceInfo)); + + u64 storage = device & 0xFFFFF00FFFFFFFF; + u32 dev_num = (device >> 32) & 0xFF; + + if (storage == ATA_HDD) // dev_hdd? + { + if (dev_num > 2) + { + return not_an_error(-5); + } + + std::string u = "unnamed"; + memcpy(buffer->name, u.c_str(), u.size()); + buffer->sector_size = 0x200; + buffer->one = 1; + buffer->flags[1] = 1; + buffer->flags[2] = 1; + buffer->flags[7] = 1; + + // set partition size based on dev_num + // stole these sizes from kernel dump, unknown if they are 100% correct + // vsh reports only 2 partitions even though there is 3 sizes + switch (dev_num) + { + case 0: + buffer->sector_count = 0x2542EAB0; // possibly total size + break; + case 1: + buffer->sector_count = 0x24FAEA98; // which makes this hdd0 + break; + case 2: + buffer->sector_count = 0x3FFFF8; // and this one hdd1 + break; + } + } + else if (storage == BDVD_DRIVE) // dev_bdvd? + { + if (dev_num > 0) + { + return not_an_error(-5); + } + + std::string u = "unnamed"; + memcpy(buffer->name, u.c_str(), u.size()); + buffer->sector_count = 0x4D955; + buffer->sector_size = 0x800; + buffer->one = 1; + buffer->flags[1] = 0; + buffer->flags[2] = 1; + buffer->flags[7] = 1; + } + else if (storage == USB_MASS_STORAGE_1(0)) + { + if (dev_num > 0) + { + return not_an_error(-5); + } + + std::string u = "unnamed"; + memcpy(buffer->name, u.c_str(), u.size()); + /*buffer->sector_count = 0x4D955;*/ + buffer->sector_size = 0x200; + buffer->one = 1; + buffer->flags[1] = 0; + buffer->flags[2] = 1; + buffer->flags[7] = 1; + } + else if (storage == NAND_FLASH) + { + if (dev_num > 6) + { + return not_an_error(-5); + } + + std::string u = "unnamed"; + memcpy(buffer->name, u.c_str(), u.size()); + buffer->sector_size = 0x200; + buffer->one = 1; + buffer->flags[1] = 1; + buffer->flags[2] = 1; + buffer->flags[7] = 1; + + // see ata_hdd for explanation + switch (dev_num) + { + case 0: buffer->sector_count = 0x80000; + break; + case 1: buffer->sector_count = 0x75F8; + break; + case 2: buffer->sector_count = 0x63E00; + break; + case 3: buffer->sector_count = 0x8000; + break; + case 4: buffer->sector_count = 0x400; + break; + case 5: buffer->sector_count = 0x2000; + break; + case 6: buffer->sector_count = 0x200; + break; + } + } + else if (storage == NOR_FLASH) + { + if (dev_num > 3) + { + return not_an_error(-5); + } + + std::string u = "unnamed"; + memcpy(buffer->name, u.c_str(), u.size()); + buffer->sector_size = 0x200; + buffer->one = 1; + buffer->flags[1] = 0; + buffer->flags[2] = 1; + buffer->flags[7] = 1; + + // see ata_hdd for explanation + switch (dev_num) + { + case 0: buffer->sector_count = 0x8000; + break; + case 1: buffer->sector_count = 0x77F8; + break; + case 2: buffer->sector_count = 0x100; // offset, 0x20000 + break; + case 3: buffer->sector_count = 0x400; + break; + } + } + else if (storage == NAND_UNK) + { + if (dev_num > 1) + { + return not_an_error(-5); + } + + std::string u = "unnamed"; + memcpy(buffer->name, u.c_str(), u.size()); + buffer->sector_size = 0x800; + buffer->one = 1; + buffer->flags[1] = 0; + buffer->flags[2] = 1; + buffer->flags[7] = 1; + + // see ata_hdd for explanation + switch (dev_num) + { + case 0: buffer->sector_count = 0x7FFFFFFF; + break; + } + } + else + { + sys_storage.error("sys_storage_get_device_info(device=0x%x, buffer=*0x%x)", device, buffer); + } + return CELL_OK; } @@ -88,6 +335,9 @@ error_code sys_storage_get_device_config(vm::ptr storages, vm::ptr dev { sys_storage.todo("sys_storage_get_device_config(storages=*0x%x, devices=*0x%x)", storages, devices); + if (storages) *storages = 6; else return CELL_EFAULT; + if (devices) *devices = 17; else return CELL_EFAULT; + return CELL_OK; } @@ -95,6 +345,44 @@ error_code sys_storage_report_devices(u32 storages, u32 start, u32 devices, vm:: { sys_storage.todo("sys_storage_report_devices(storages=0x%x, start=0x%x, devices=0x%x, device_ids=0x%x)", storages, start, devices, device_ids); + if (!device_ids) + { + return CELL_EFAULT; + } + + static constexpr std::array all_devs = [] + { + std::array all_devs{}; + all_devs[0] = 0x10300000000000A; + + for (int i = 0; i < 7; ++i) + { + all_devs[i + 1] = 0x100000000000001 | (static_cast(i) << 32); + } + + for (int i = 0; i < 3; ++i) + { + all_devs[i + 8] = 0x101000000000007 | (static_cast(i) << 32); + } + + all_devs[11] = 0x101000000000006; + + for (int i = 0; i < 4; ++i) + { + all_devs[i + 12] = 0x100000000000004 | (static_cast(i) << 32); + } + + all_devs[16] = 0x100000000000003; + return all_devs; + }(); + + if (!devices || start >= all_devs.size() || devices > all_devs.size() - start) + { + return CELL_EINVAL; + } + + std::copy_n(all_devs.begin() + start, devices, device_ids.get_ptr()); + return CELL_OK; } @@ -130,6 +418,9 @@ error_code sys_storage_execute_device_command(u32 fd, u64 cmd, vm::ptr cmd { sys_storage.todo("sys_storage_execute_device_command(fd=0x%x, cmd=0x%llx, cmdbuf=*0x%x, cmdbuf_size=0x%llx, databuf=*0x%x, databuf_size=0x%llx, driver_status=*0x%x)", fd, cmd, cmdbuf, cmdbuf_size, databuf, databuf_size, driver_status); + // cmd == 2 is get device info, + // databuf, first byte 0 == status ok? + // byte 1, if < 0 , not ata device return CELL_OK; } @@ -158,5 +449,6 @@ error_code sys_storage_set_emulated_speed() { sys_storage.todo("sys_storage_set_emulated_speed()"); - return CELL_OK; + // todo: only debug kernel has this + return CELL_ENOSYS; } diff --git a/rpcs3/Emu/Cell/lv2/sys_storage.h b/rpcs3/Emu/Cell/lv2/sys_storage.h index b5f87ad6d6..5177247933 100644 --- a/rpcs3/Emu/Cell/lv2/sys_storage.h +++ b/rpcs3/Emu/Cell/lv2/sys_storage.h @@ -3,6 +3,44 @@ #include "Emu/Memory/vm_ptr.h" #include "Emu/Cell/ErrorCodes.h" +enum Devices : u64 +{ + ATA_HDD = 0x101000000000007, + BDVD_DRIVE = 0x101000000000006, + PATA0_HDD_DRIVE = 0x101000000000008, + PATA0_BDVD_DRIVE = BDVD_DRIVE, + PATA1_HDD_DRIVE = ATA_HDD, + BUILTIN_FLASH = 0x100000000000001, + NAND_FLASH = BUILTIN_FLASH, + NAND_UNK = 0x100000000000003, + NOR_FLASH = 0x100000000000004, + MEMORY_STICK = 0x103000000000010, + SD_CARD = 0x103000100000010, + COMPACT_FLASH = 0x103000200000010, + USB_MASS_STORAGE_1_BASE = 0x10300000000000A, + USB_MASS_STORAGE_2_BASE = 0x10300000000001F, +}; + +struct lv2_storage +{ + static const u32 id_base = 0x45000000; + static const u32 id_step = 1; + static const u32 id_count = 2048; + + const u64 device_id; + const fs::file file; + const u64 mode; + const u64 flags; + + lv2_storage(u64 device_id, fs::file&& file, u64 mode, u64 flags) + : device_id(device_id) + , file(std::move(file)) + , mode(mode) + , flags(flags) + { + } +}; + struct StorageDeviceInfo { u8 name[0x20]; // 0x0 @@ -14,6 +52,9 @@ struct StorageDeviceInfo u8 flags[8]; // 0x38 }; +#define USB_MASS_STORAGE_1(n) (USB_MASS_STORAGE_1_BASE + n) /* For 0-5 */ +#define USB_MASS_STORAGE_2(n) (USB_MASS_STORAGE_2_BASE + (n - 6)) /* For 6-127 */ + // SysCalls error_code sys_storage_open(u64 device, u64 mode, vm::ptr fd, u64 flags);