1 // Copyright 2018 yuzu emulator team
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <fmt/format.h>
6 #include "common/file_util.h"
7 #include "core/file_sys/bis_factory.h"
8 #include "core/file_sys/mode.h"
9 #include "core/file_sys/registered_cache.h"
10 #include "core/file_sys/vfs.h"
11
12 namespace FileSys {
13
14 constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB
15 constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB
16 constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB
17
BISFactory(VirtualDir nand_root_,VirtualDir load_root_,VirtualDir dump_root_)18 BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
19 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
20 dump_root(std::move(dump_root_)),
21 sysnand_cache(std::make_unique<RegisteredCache>(
22 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
23 usrnand_cache(std::make_unique<RegisteredCache>(
24 GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))),
25 sysnand_placeholder(std::make_unique<PlaceholderCache>(
26 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/placehld"))),
27 usrnand_placeholder(std::make_unique<PlaceholderCache>(
28 GetOrCreateDirectoryRelative(nand_root, "/user/Contents/placehld"))) {}
29
30 BISFactory::~BISFactory() = default;
31
GetSystemNANDContentDirectory() const32 VirtualDir BISFactory::GetSystemNANDContentDirectory() const {
33 return GetOrCreateDirectoryRelative(nand_root, "/system/Contents");
34 }
35
GetUserNANDContentDirectory() const36 VirtualDir BISFactory::GetUserNANDContentDirectory() const {
37 return GetOrCreateDirectoryRelative(nand_root, "/user/Contents");
38 }
39
GetSystemNANDContents() const40 RegisteredCache* BISFactory::GetSystemNANDContents() const {
41 return sysnand_cache.get();
42 }
43
GetUserNANDContents() const44 RegisteredCache* BISFactory::GetUserNANDContents() const {
45 return usrnand_cache.get();
46 }
47
GetSystemNANDPlaceholder() const48 PlaceholderCache* BISFactory::GetSystemNANDPlaceholder() const {
49 return sysnand_placeholder.get();
50 }
51
GetUserNANDPlaceholder() const52 PlaceholderCache* BISFactory::GetUserNANDPlaceholder() const {
53 return usrnand_placeholder.get();
54 }
55
GetModificationLoadRoot(u64 title_id) const56 VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
57 // LayeredFS doesn't work on updates and title id-less homebrew
58 if (title_id == 0 || (title_id & 0xFFF) == 0x800)
59 return nullptr;
60 return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
61 }
62
GetModificationDumpRoot(u64 title_id) const63 VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
64 if (title_id == 0)
65 return nullptr;
66 return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
67 }
68
OpenPartition(BisPartitionId id) const69 VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
70 switch (id) {
71 case BisPartitionId::CalibrationFile:
72 return GetOrCreateDirectoryRelative(nand_root, "/prodinfof");
73 case BisPartitionId::SafeMode:
74 return GetOrCreateDirectoryRelative(nand_root, "/safe");
75 case BisPartitionId::System:
76 return GetOrCreateDirectoryRelative(nand_root, "/system");
77 case BisPartitionId::User:
78 return GetOrCreateDirectoryRelative(nand_root, "/user");
79 default:
80 return nullptr;
81 }
82 }
83
OpenPartitionStorage(BisPartitionId id,VirtualFilesystem file_system) const84 VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id,
85 VirtualFilesystem file_system) const {
86 auto& keys = Core::Crypto::KeyManager::Instance();
87 Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory(
88 Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
89 keys.PopulateFromPartitionData(pdm);
90
91 switch (id) {
92 case BisPartitionId::CalibrationBinary:
93 return pdm.GetDecryptedProdInfo();
94 case BisPartitionId::BootConfigAndPackage2Part1:
95 case BisPartitionId::BootConfigAndPackage2Part2:
96 case BisPartitionId::BootConfigAndPackage2Part3:
97 case BisPartitionId::BootConfigAndPackage2Part4:
98 case BisPartitionId::BootConfigAndPackage2Part5:
99 case BisPartitionId::BootConfigAndPackage2Part6: {
100 const auto new_id = static_cast<u8>(id) -
101 static_cast<u8>(BisPartitionId::BootConfigAndPackage2Part1) +
102 static_cast<u8>(Core::Crypto::Package2Type::NormalMain);
103 return pdm.GetPackage2Raw(static_cast<Core::Crypto::Package2Type>(new_id));
104 }
105 default:
106 return nullptr;
107 }
108 }
109
GetImageDirectory() const110 VirtualDir BISFactory::GetImageDirectory() const {
111 return GetOrCreateDirectoryRelative(nand_root, "/user/Album");
112 }
113
GetSystemNANDFreeSpace() const114 u64 BISFactory::GetSystemNANDFreeSpace() const {
115 const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
116 if (sys_dir == nullptr) {
117 return GetSystemNANDTotalSpace();
118 }
119
120 return GetSystemNANDTotalSpace() - sys_dir->GetSize();
121 }
122
GetSystemNANDTotalSpace() const123 u64 BISFactory::GetSystemNANDTotalSpace() const {
124 return NAND_SYSTEM_SIZE;
125 }
126
GetUserNANDFreeSpace() const127 u64 BISFactory::GetUserNANDFreeSpace() const {
128 // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes.
129 // Set the free space to be 1 MiB less than the total as a workaround to this issue.
130 return GetUserNANDTotalSpace() - 0x100000;
131 }
132
GetUserNANDTotalSpace() const133 u64 BISFactory::GetUserNANDTotalSpace() const {
134 return NAND_USER_SIZE;
135 }
136
GetFullNANDTotalSpace() const137 u64 BISFactory::GetFullNANDTotalSpace() const {
138 return NAND_TOTAL_SIZE;
139 }
140
GetBCATDirectory(u64 title_id) const141 VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const {
142 return GetOrCreateDirectoryRelative(nand_root,
143 fmt::format("/system/save/bcat/{:016X}", title_id));
144 }
145
146 } // namespace FileSys
147