|
| 1 | +/// E-Ticket System Supported Ioctls |
| 2 | +pub enum Ioctl { |
| 3 | + AddTicket, |
| 4 | + AddTitleStart, |
| 5 | + AddContentStart, |
| 6 | + AddContentData, |
| 7 | + AddContentFinish, |
| 8 | + AddTitleFinish, |
| 9 | + GetDeviceId, |
| 10 | + Launch, |
| 11 | + OpenActiveTitleContent, |
| 12 | + ReadContent, |
| 13 | + CloseContent, |
| 14 | + GetOwnedTitleCount, |
| 15 | + GetOwnedTitles, |
| 16 | + GetTitleCount, |
| 17 | + GetTitles, |
| 18 | + GetViewCount, |
| 19 | + GetViews, |
| 20 | + GetTitleMetadataViewCount, |
| 21 | + GetTitleMetadataViews, |
| 22 | + GetConsumption, |
| 23 | + Deletetitle, |
| 24 | + DeleteTicket, |
| 25 | + DiskInterfaceGetTitleMetadataViewSize, |
| 26 | + DiskInterfaceGetTitleMetadataView, |
| 27 | + DiskInterfaceGetTicketView, |
| 28 | + DiskInterfaceVerify, |
| 29 | + GetTitleDir, |
| 30 | + GetDeviceCertificate, |
| 31 | + ImportBoot, |
| 32 | + GetTitleId, |
| 33 | + SetUid, |
| 34 | + DeleteTitleContent, |
| 35 | + SeekContent, |
| 36 | + OpenContent, |
| 37 | + LauchBackwardsCompatibility, |
| 38 | + ExportTitleInitalize, |
| 39 | + ExportContentBegin, |
| 40 | + ExportContentData, |
| 41 | + ExportContentEnd, |
| 42 | + ExportTitleDone, |
| 43 | + AddTitleMetadata, |
| 44 | + Encrypt, |
| 45 | + Decrypt, |
| 46 | + GetBoot2Version, |
| 47 | + AddTitleCancel, |
| 48 | + Sign, |
| 49 | + VerifySign, |
| 50 | + GetStoredContentCount, |
| 51 | + GetStoredContents, |
| 52 | + GetStoredTitleMetadataSize, |
| 53 | + GetStoredTitleMetadata, |
| 54 | + GetSharedContentCount, |
| 55 | + GetSharedContents, |
| 56 | + DeleteSharedContents, |
| 57 | + DiskInterfaceGetTitleMetadataSize, |
| 58 | + DiskInterfaceGetTitleMetadata, |
| 59 | + DiskInterfaceVerifyWithView, |
| 60 | + SetupStreamKey, |
| 61 | + DeleteStreamKey, |
| 62 | + DeleteContent, |
| 63 | + // Invalid3F |
| 64 | + GetVersion0TicketFromView, |
| 65 | + // Unknown41, |
| 66 | + // Unknown42, |
| 67 | + GetTicketSizeFromView, |
| 68 | + GetTicketFromView, |
| 69 | + CheckKoreaRegion, |
| 70 | +} |
| 71 | + |
| 72 | +impl From<Ioctl> for i32 { |
| 73 | + fn from(value: Ioctl) -> Self { |
| 74 | + match value { |
| 75 | + Ioctl::AddTicket => todo!(), |
| 76 | + Ioctl::AddTitleStart => todo!(), |
| 77 | + Ioctl::AddContentStart => todo!(), |
| 78 | + Ioctl::AddContentData => todo!(), |
| 79 | + Ioctl::AddContentFinish => todo!(), |
| 80 | + Ioctl::AddTitleFinish => todo!(), |
| 81 | + Ioctl::GetDeviceId => todo!(), |
| 82 | + Ioctl::Launch => todo!(), |
| 83 | + Ioctl::OpenActiveTitleContent => todo!(), |
| 84 | + Ioctl::ReadContent => todo!(), |
| 85 | + Ioctl::CloseContent => todo!(), |
| 86 | + Ioctl::GetOwnedTitleCount => todo!(), |
| 87 | + Ioctl::GetOwnedTitles => todo!(), |
| 88 | + Ioctl::GetTitleCount => 14, //0xE |
| 89 | + Ioctl::GetTitles => 15, //0xF |
| 90 | + Ioctl::GetViewCount => todo!(), |
| 91 | + Ioctl::GetViews => todo!(), |
| 92 | + Ioctl::GetTitleMetadataViewCount => todo!(), |
| 93 | + Ioctl::GetTitleMetadataViews => todo!(), |
| 94 | + Ioctl::GetConsumption => todo!(), |
| 95 | + Ioctl::Deletetitle => todo!(), |
| 96 | + Ioctl::DeleteTicket => todo!(), |
| 97 | + Ioctl::DiskInterfaceGetTitleMetadataViewSize => todo!(), |
| 98 | + Ioctl::DiskInterfaceGetTitleMetadataView => todo!(), |
| 99 | + Ioctl::DiskInterfaceGetTicketView => todo!(), |
| 100 | + Ioctl::DiskInterfaceVerify => todo!(), |
| 101 | + Ioctl::GetTitleDir => todo!(), |
| 102 | + Ioctl::GetDeviceCertificate => todo!(), |
| 103 | + Ioctl::ImportBoot => todo!(), |
| 104 | + Ioctl::GetTitleId => todo!(), |
| 105 | + Ioctl::SetUid => todo!(), |
| 106 | + Ioctl::DeleteTitleContent => todo!(), |
| 107 | + Ioctl::SeekContent => todo!(), |
| 108 | + Ioctl::OpenContent => todo!(), |
| 109 | + Ioctl::LauchBackwardsCompatibility => todo!(), |
| 110 | + Ioctl::ExportTitleInitalize => todo!(), |
| 111 | + Ioctl::ExportContentBegin => todo!(), |
| 112 | + Ioctl::ExportContentData => todo!(), |
| 113 | + Ioctl::ExportContentEnd => todo!(), |
| 114 | + Ioctl::ExportTitleDone => todo!(), |
| 115 | + Ioctl::AddTitleMetadata => todo!(), |
| 116 | + Ioctl::Encrypt => todo!(), |
| 117 | + Ioctl::Decrypt => todo!(), |
| 118 | + Ioctl::GetBoot2Version => todo!(), |
| 119 | + Ioctl::AddTitleCancel => todo!(), |
| 120 | + Ioctl::Sign => todo!(), |
| 121 | + Ioctl::VerifySign => todo!(), |
| 122 | + Ioctl::GetStoredContentCount => todo!(), |
| 123 | + Ioctl::GetStoredContents => todo!(), |
| 124 | + Ioctl::GetStoredTitleMetadataSize => todo!(), |
| 125 | + Ioctl::GetStoredTitleMetadata => todo!(), |
| 126 | + Ioctl::GetSharedContentCount => todo!(), |
| 127 | + Ioctl::GetSharedContents => todo!(), |
| 128 | + Ioctl::DeleteSharedContents => todo!(), |
| 129 | + Ioctl::DiskInterfaceGetTitleMetadataSize => todo!(), |
| 130 | + Ioctl::DiskInterfaceGetTitleMetadata => todo!(), |
| 131 | + Ioctl::DiskInterfaceVerifyWithView => todo!(), |
| 132 | + Ioctl::SetupStreamKey => todo!(), |
| 133 | + Ioctl::DeleteStreamKey => todo!(), |
| 134 | + Ioctl::DeleteContent => todo!(), |
| 135 | + Ioctl::GetVersion0TicketFromView => todo!(), |
| 136 | + Ioctl::GetTicketSizeFromView => todo!(), |
| 137 | + Ioctl::GetTicketFromView => todo!(), |
| 138 | + Ioctl::CheckKoreaRegion => todo!(), |
| 139 | + } |
| 140 | + } |
| 141 | +} |
| 142 | + |
| 143 | +static DEV_ES: &CStr = c"/dev/es"; |
| 144 | + |
| 145 | +use core::ffi::CStr; |
| 146 | + |
| 147 | +use alloc::vec::Vec; |
| 148 | + |
| 149 | +use crate::ios; |
| 150 | + |
| 151 | +pub fn get_title_count() -> Result<u32, ios::Error> { |
| 152 | + let es = ios::open(DEV_ES, ios::Mode::None)?; |
| 153 | + |
| 154 | + let mut out_buf = [0u8; 4]; |
| 155 | + ios::ioctlv::<0, 1, 1>(es, Ioctl::GetTitleCount, &[], &mut [&mut out_buf])?; |
| 156 | + |
| 157 | + let _ = ios::close(es); |
| 158 | + |
| 159 | + Ok(u32::from_be_bytes(out_buf)) |
| 160 | +} |
| 161 | + |
| 162 | +pub fn get_titles(title_count: u32) -> Result<Vec<u64>, ios::Error> { |
| 163 | + let es = ios::open(DEV_ES, ios::Mode::None)?; |
| 164 | + |
| 165 | + // TODO: Avoid allocation |
| 166 | + let mut out_buf = alloc::vec![0u8; title_count as usize * core::mem::size_of::<u64>()]; |
| 167 | + |
| 168 | + let count: [u8; 4] = title_count.to_be_bytes(); |
| 169 | + ios::ioctlv::<1, 1, 2>(es, Ioctl::GetTitles, &[&count], &mut [&mut out_buf[..]])?; |
| 170 | + |
| 171 | + let _ = ios::close(es); |
| 172 | + |
| 173 | + // TODO: Avoid allocation |
| 174 | + Ok(out_buf |
| 175 | + .chunks_exact(core::mem::size_of::<u64>()) |
| 176 | + .map(|bytes| u64::from_be_bytes(bytes.try_into().expect("should fit"))) |
| 177 | + .collect()) |
| 178 | +} |
| 179 | + |
| 180 | +pub fn get_stored_title_metadata_size(title_id: u64) -> Result<u32, ios::Error> { |
| 181 | + let es = ios::open(DEV_ES, ios::Mode::None)?; |
| 182 | + |
| 183 | + let in_buf = title_id.to_be_bytes(); |
| 184 | + let mut out_buf = [0u8; 4]; |
| 185 | + ios::ioctlv::<1, 1, 2>( |
| 186 | + es, |
| 187 | + Ioctl::GetStoredTitleMetadataSize, |
| 188 | + &[&in_buf], |
| 189 | + &mut [&mut out_buf], |
| 190 | + )?; |
| 191 | + |
| 192 | + let _ = ios::close(es); |
| 193 | + |
| 194 | + Ok(u32::from_be_bytes( |
| 195 | + out_buf.try_into().map_err(|_| ios::Error::Invalid)?, |
| 196 | + )) |
| 197 | +} |
| 198 | + |
| 199 | +// TODO: Proper enuming since there are different signature types and differing sizes for them |
| 200 | +pub fn get_stored_title_metadata(title_id: u64, size: u32) -> Result<Vec<u8>, ios::Error> { |
| 201 | + let es = ios::open(DEV_ES, ios::Mode::None)?; |
| 202 | + |
| 203 | + let title_buf = title_id.to_be_bytes(); |
| 204 | + let size_buf = size.to_be_bytes(); |
| 205 | + let size_usize: usize = usize::try_from(size).map_err(|_| ios::Error::Invalid)?; |
| 206 | + // TODO: Avoid allocation |
| 207 | + let mut out_buf = alloc::vec![0u8; size_usize]; |
| 208 | + ios::ioctlv::<2, 1, 3>( |
| 209 | + es, |
| 210 | + Ioctl::GetStoredTitleMetadata, |
| 211 | + &[&title_buf, &size_buf], |
| 212 | + &mut [&mut out_buf[..]], |
| 213 | + )?; |
| 214 | + |
| 215 | + let _ = ios::close(es); |
| 216 | + |
| 217 | + Ok(out_buf) |
| 218 | +} |
0 commit comments