mirror of
				https://github.com/Atmosphere-NX/Atmosphere.git
				synced 2025-10-31 11:15:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			159 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * 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 <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
|  
 | |
| #pragma once
 | |
| #include <switch.h>
 | |
| #include <cstring>
 | |
| #include <stratosphere.hpp>
 | |
| 
 | |
| #include "fs_istorage.hpp"
 | |
| 
 | |
| /* Represents a sectored storage. */
 | |
| template<u64 SectorSize> 
 | |
| 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 = ResultSuccess;
 | |
|             u8 *buffer = static_cast<u8 *>(_buffer);
 | |
|             this->Seek(offset);
 | |
|             
 | |
|             if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
 | |
|                 /* Fast case. */
 | |
|                 return ProxyStorage::Read(buffer, size, 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 = ResultSuccess;
 | |
|             u8 *buffer = static_cast<u8 *>(_buffer);
 | |
|             this->Seek(offset);
 | |
|             
 | |
|             if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
 | |
|                 /* Fast case. */
 | |
|                 return ProxyStorage::Write(buffer, size, 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>;
 | |
|     
 | |
|     public:
 | |
|         static constexpr u64 BctEndOffset = 0xFC000;
 | |
|         static constexpr u64 BctSize = 0x4000;
 | |
|         static constexpr u64 BctPubkStart = 0x210;
 | |
|         static constexpr u64 BctPubkSize = 0x100;
 | |
|         static constexpr u64 BctPubkEnd = BctPubkStart + BctPubkSize;
 | |
|         
 | |
|         static constexpr u64 EksStart = 0x180000;
 | |
|         static constexpr u64 EksSize = 0x4000;
 | |
|         static constexpr u64 EksEnd = EksStart + EksSize;
 | |
|     private:
 | |
|         u64 title_id;
 | |
|     private:
 | |
|         bool CanModifyBctPubks();
 | |
|     public:
 | |
|         Boot0Storage(FsStorage *s, u64 t) : Base(s), title_id(t) { }
 | |
|         Boot0Storage(FsStorage s, u64 t) : Base(s), title_id(t) { }
 | |
|     public:
 | |
|         virtual Result Read(void *_buffer, size_t size, u64 offset) override; 
 | |
|         virtual Result Write(void *_buffer, size_t size, u64 offset) override;
 | |
| }; |