[VFS/Kernel] Fixes to allow games to make use of cache partitions
Happy new year! Here's my first commit of the 2020s :)
With these fixes, Halo 3 Epsilon will now write cached map data & other things (autosaves/datamine...) to the cache0/cache1 partitions, (as long as mount_cache cvar is set)
(Halo 3 retail will also write some things to cache with this, but oddly doesn't cache map stuff... which is strange because Epsilon was built only a day or two after the retail build, so I'm not sure why it'd work differently...
Maybe retail needs a TU applied for it to work or something like that)
Other games should hopefully work with cache now too (AFAIK the problem was in SDK library code, that a lot of games probably share)
No idea if this will actually improve anything though, but at least things will work closer to what games expect :)
The way this works is by tricking the cache-partition code (staticly linked into the game exe) into thinking that the Partition0/Cache0/Cache1 devices are valid.
To do that I made another kind of VFS device, the NullDevice, which just takes in a list of paths to handle.
Whenever an IO request is made to one of these paths, the NullDevice can simply pretend to the game that everything was successful, which satisfies the requirements needed for caching.
It also makes use of another trick: setting TitleInsecureCacheDrive XEX permission, which seems to skip a huge chunk of cache-init code (STFC filesystem device registration & stuff like that)
I'm not sure if this would work with every single revision of the STFC/cache code though...
At least in Halo 3 the retail code will handle the TitleInsecureCacheDrive case for us fine, but maybe older/more recent versions don't include functionality for it, need to look into it some more.
(I did try an impl. without needing this permission months ago, got pretty far with it but got caught on one tiny issue that I couldn't figure out... too bad I didn't find out about this permission earlier!)
2020-01-01 18:11:24 +00:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
|
|
******************************************************************************
|
|
|
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
|
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
|
|
******************************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "xenia/vfs/devices/null_file.h"
|
|
|
|
|
2020-01-20 01:10:43 +00:00
|
|
|
#include "xenia/vfs/devices/null_device.h"
|
[VFS/Kernel] Fixes to allow games to make use of cache partitions
Happy new year! Here's my first commit of the 2020s :)
With these fixes, Halo 3 Epsilon will now write cached map data & other things (autosaves/datamine...) to the cache0/cache1 partitions, (as long as mount_cache cvar is set)
(Halo 3 retail will also write some things to cache with this, but oddly doesn't cache map stuff... which is strange because Epsilon was built only a day or two after the retail build, so I'm not sure why it'd work differently...
Maybe retail needs a TU applied for it to work or something like that)
Other games should hopefully work with cache now too (AFAIK the problem was in SDK library code, that a lot of games probably share)
No idea if this will actually improve anything though, but at least things will work closer to what games expect :)
The way this works is by tricking the cache-partition code (staticly linked into the game exe) into thinking that the Partition0/Cache0/Cache1 devices are valid.
To do that I made another kind of VFS device, the NullDevice, which just takes in a list of paths to handle.
Whenever an IO request is made to one of these paths, the NullDevice can simply pretend to the game that everything was successful, which satisfies the requirements needed for caching.
It also makes use of another trick: setting TitleInsecureCacheDrive XEX permission, which seems to skip a huge chunk of cache-init code (STFC filesystem device registration & stuff like that)
I'm not sure if this would work with every single revision of the STFC/cache code though...
At least in Halo 3 the retail code will handle the TitleInsecureCacheDrive case for us fine, but maybe older/more recent versions don't include functionality for it, need to look into it some more.
(I did try an impl. without needing this permission months ago, got pretty far with it but got caught on one tiny issue that I couldn't figure out... too bad I didn't find out about this permission earlier!)
2020-01-01 18:11:24 +00:00
|
|
|
#include "xenia/vfs/devices/null_entry.h"
|
|
|
|
|
|
|
|
namespace xe {
|
|
|
|
namespace vfs {
|
|
|
|
|
|
|
|
NullFile::NullFile(uint32_t file_access, NullEntry* entry)
|
|
|
|
: File(file_access, entry) {}
|
|
|
|
|
|
|
|
NullFile::~NullFile() = default;
|
|
|
|
|
|
|
|
void NullFile::Destroy() { delete this; }
|
|
|
|
|
|
|
|
X_STATUS NullFile::ReadSync(void* buffer, size_t buffer_length,
|
|
|
|
size_t byte_offset, size_t* out_bytes_read) {
|
|
|
|
if (!(file_access_ & FileAccess::kFileReadData)) {
|
|
|
|
return X_STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return X_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
X_STATUS NullFile::WriteSync(const void* buffer, size_t buffer_length,
|
|
|
|
size_t byte_offset, size_t* out_bytes_written) {
|
|
|
|
if (!(file_access_ &
|
|
|
|
(FileAccess::kFileWriteData | FileAccess::kFileAppendData))) {
|
|
|
|
return X_STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
2020-01-20 01:10:43 +00:00
|
|
|
// Check if game is writing a FATX header...
|
|
|
|
if (byte_offset == 0 && buffer_length >= (4 * 3)) {
|
|
|
|
auto* header = (uint32_t*)buffer;
|
|
|
|
if (xe::load_and_swap<uint32_t>(header) == 0x58544146) {
|
|
|
|
// This is a FATX header - read the SectorsPerCluster value from it
|
|
|
|
// Game will try reading this back through NtQueryVolumeInformationFile
|
|
|
|
// later on, if it doesn't match, cache partition mount won't succeed
|
|
|
|
auto sectors_per_cluster = xe::byte_swap(header[2]);
|
|
|
|
// Update NullDevice with the SectorsPerCluster value
|
|
|
|
auto* null_device = (NullDevice*)entry_->device();
|
|
|
|
null_device->sectors_per_allocation_unit(sectors_per_cluster);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[VFS/Kernel] Fixes to allow games to make use of cache partitions
Happy new year! Here's my first commit of the 2020s :)
With these fixes, Halo 3 Epsilon will now write cached map data & other things (autosaves/datamine...) to the cache0/cache1 partitions, (as long as mount_cache cvar is set)
(Halo 3 retail will also write some things to cache with this, but oddly doesn't cache map stuff... which is strange because Epsilon was built only a day or two after the retail build, so I'm not sure why it'd work differently...
Maybe retail needs a TU applied for it to work or something like that)
Other games should hopefully work with cache now too (AFAIK the problem was in SDK library code, that a lot of games probably share)
No idea if this will actually improve anything though, but at least things will work closer to what games expect :)
The way this works is by tricking the cache-partition code (staticly linked into the game exe) into thinking that the Partition0/Cache0/Cache1 devices are valid.
To do that I made another kind of VFS device, the NullDevice, which just takes in a list of paths to handle.
Whenever an IO request is made to one of these paths, the NullDevice can simply pretend to the game that everything was successful, which satisfies the requirements needed for caching.
It also makes use of another trick: setting TitleInsecureCacheDrive XEX permission, which seems to skip a huge chunk of cache-init code (STFC filesystem device registration & stuff like that)
I'm not sure if this would work with every single revision of the STFC/cache code though...
At least in Halo 3 the retail code will handle the TitleInsecureCacheDrive case for us fine, but maybe older/more recent versions don't include functionality for it, need to look into it some more.
(I did try an impl. without needing this permission months ago, got pretty far with it but got caught on one tiny issue that I couldn't figure out... too bad I didn't find out about this permission earlier!)
2020-01-01 18:11:24 +00:00
|
|
|
return X_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
X_STATUS NullFile::SetLength(size_t length) {
|
|
|
|
if (!(file_access_ & FileAccess::kFileWriteData)) {
|
|
|
|
return X_STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return X_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vfs
|
|
|
|
} // namespace xe
|