diff --git a/stratosphere/fs_mitm/source/fs_istorage.hpp b/stratosphere/fs_mitm/source/fs_istorage.hpp
index 23233e27f..8bd44cdd2 100644
--- a/stratosphere/fs_mitm/source/fs_istorage.hpp
+++ b/stratosphere/fs_mitm/source/fs_istorage.hpp
@@ -120,7 +120,7 @@ class ProxyStorage : public IStorage {
ProxyStorage(FsStorage s) {
this->base_storage = new FsStorage(s);
};
- ~ProxyStorage() {
+ virtual ~ProxyStorage() {
fsStorageClose(base_storage);
delete base_storage;
};
@@ -155,7 +155,7 @@ class ROProxyStorage : public IROStorage {
ROProxyStorage(FsStorage s) {
this->base_storage = new FsStorage(s);
};
- ~ROProxyStorage() {
+ virtual ~ROProxyStorage() {
fsStorageClose(base_storage);
delete base_storage;
};
diff --git a/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp
new file mode 100644
index 000000000..d06351175
--- /dev/null
+++ b/stratosphere/fs_mitm/source/fsmitm_boot0storage.hpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+#include
+
+#include "fs_istorage.hpp"
+
+/* Represents a sectored storage. */
+template
+class SectoredProxyStorage : public ProxyStorage {
+ private:
+ u64 cur_seek = 0;
+ u64 cur_sector = 0;
+ u64 cur_sector_ofs = 0;
+ u8 sector_buf[SectorSize];
+ private:
+ void Seek(u64 offset) {
+ this->cur_sector_ofs = offset % SectorSize;
+ this->cur_seek = offset - this->cur_sector_ofs;
+ }
+ public:
+ SectoredProxyStorage(FsStorage *s) : ProxyStorage(s) { }
+ SectoredProxyStorage(FsStorage s) : ProxyStorage(s) { }
+ public:
+ virtual Result Read(void *_buffer, size_t size, u64 offset) override {
+ Result rc = 0;
+ u8 *buffer = static_cast(_buffer);
+ this->Seek(offset);
+
+ if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) {
+ return rc;
+ }
+
+ if (size + this->cur_sector_ofs <= SectorSize) {
+ memcpy(buffer, sector_buf + this->cur_sector_ofs, size);
+ } else {
+ /* Leaving the sector... */
+ size_t ofs = SectorSize - this->cur_sector_ofs;
+ memcpy(buffer, sector_buf + this->cur_sector_ofs, ofs);
+ size -= ofs;
+
+ /* We're guaranteed alignment, here. */
+ const size_t aligned_remaining_size = size - (size % SectorSize);
+ if (aligned_remaining_size) {
+ if (R_FAILED((rc = ProxyStorage::Read(buffer + ofs, aligned_remaining_size, offset + ofs)))) {
+ return rc;
+ }
+ ofs += aligned_remaining_size;
+ size -= aligned_remaining_size;
+ }
+
+ /* Read any leftover data. */
+ if (size) {
+ if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) {
+ return rc;
+ }
+ memcpy(buffer + ofs, sector_buf, size);
+ }
+ }
+
+ return rc;
+ };
+ virtual Result Write(void *_buffer, size_t size, u64 offset) override {
+ Result rc = 0;
+ u8 *buffer = static_cast(_buffer);
+ this->Seek(offset);
+
+ if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) {
+ return rc;
+ }
+
+
+ if (size + this->cur_sector_ofs <= SectorSize) {
+ memcpy(this->sector_buf + this->cur_sector_ofs, buffer, size);
+ rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek);
+ } else {
+ /* Leaving the sector... */
+ size_t ofs = SectorSize - this->cur_sector_ofs;
+ memcpy(this->sector_buf + this->cur_sector_ofs, buffer, ofs);
+ if (R_FAILED((rc = ProxyStorage::Write(this->sector_buf, ofs, this->cur_seek)))) {
+ return rc;
+ }
+ size -= ofs;
+
+ /* We're guaranteed alignment, here. */
+ const size_t aligned_remaining_size = size - (size % SectorSize);
+ if (aligned_remaining_size) {
+ if (R_FAILED((rc = ProxyStorage::Write(buffer + ofs, aligned_remaining_size, offset + ofs)))) {
+ return rc;
+ }
+ ofs += aligned_remaining_size;
+ size -= aligned_remaining_size;
+ }
+
+ /* Write any leftover data. */
+ if (size) {
+ if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) {
+ return rc;
+ }
+ memcpy(this->sector_buf, buffer + ofs, size);
+ rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek);
+ }
+ }
+
+ return rc;
+ };
+};
+
+/* Represents an RCM-preserving BOOT0 partition. */
+class Boot0Storage : public SectoredProxyStorage<0x200> {
+ using Base = SectoredProxyStorage<0x200>;
+ private:
+ bool allow_writes;
+ private:
+ HosMutex *GetMutex() {
+ static HosMutex s_boot0_mutex;
+ return &s_boot0_mutex;
+ }
+ public:
+ Boot0Storage(FsStorage *s, bool w) : Base(s), allow_writes(w) { }
+ Boot0Storage(FsStorage s, bool w) : Base(s), allow_writes(w) { }
+
+ public:
+ virtual Result Read(void *_buffer, size_t size, u64 offset) override {
+ GetMutex()->Lock();
+ ON_SCOPE_EXIT { GetMutex()->Unlock(); };
+
+ return Base::Read(_buffer, size, offset);
+ }
+
+ virtual Result Write(void *_buffer, size_t size, u64 offset) override {
+ GetMutex()->Lock();
+ ON_SCOPE_EXIT { GetMutex()->Unlock(); };
+
+ if (!this->allow_writes) {
+ return 0x313802;
+ }
+
+ return Base::Write(_buffer, size, offset);
+ }
+};
\ No newline at end of file
diff --git a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp
index 04d0cf8d6..1a186ec4c 100644
--- a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp
+++ b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp
@@ -31,7 +31,7 @@ class RomFileStorage : public IROStorage {
RomFileStorage(FsFile f) {
this->base_file = new FsFile(f);
};
- ~RomFileStorage() {
+ virtual ~RomFileStorage() {
fsFileClose(base_file);
delete base_file;
};
diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp
index 505af638b..ccf29db94 100644
--- a/stratosphere/fs_mitm/source/fsmitm_service.cpp
+++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp
@@ -24,6 +24,7 @@
#include "fs_shim.h"
#include "fsmitm_utils.hpp"
+#include "fsmitm_boot0storage.hpp"
#include "fsmitm_romstorage.hpp"
#include "fsmitm_layeredrom.hpp"
@@ -98,11 +99,16 @@ Result FsMitmService::OpenBisStorage(Out> out
FsStorage bis_storage;
rc = fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id);
if (R_SUCCEEDED(rc)) {
- if (this->title_id >= 0x0100000000001000) {
- storage = std::make_shared(new ROProxyStorage(bis_storage));
+ const bool allow_writes = this->title_id < 0x0100000000001000;
+ if (bis_partition_id == BisStorageId_Boot0) {
+ storage = std::make_shared(new Boot0Storage(bis_storage, allow_writes));
} else {
- /* Sysmodules should still be allowed to read and write. */
- storage = std::make_shared(new ProxyStorage(bis_storage));
+ if (allow_writes) {
+ storage = std::make_shared(new ROProxyStorage(bis_storage));
+ } else {
+ /* Sysmodules should still be allowed to read and write. */
+ storage = std::make_shared(new ProxyStorage(bis_storage));
+ }
}
if (out_storage.IsDomain()) {
out_domain_id = bis_storage.s.object_id;