diff --git a/xtaf/xtaf.h b/xtaf/xtaf.h index 558c875..bbe2ae5 100644 --- a/xtaf/xtaf.h +++ b/xtaf/xtaf.h @@ -37,9 +37,8 @@ struct _x_hdd_security_sector_s { unsigned char ms_logo_hash[0x14]; uint32_t number_of_sector; unsigned char signature[0x100]; - uint32_t ms_logo_size; - void * ms_logo; -}; + unsigned char padding[0xa4]; +}; // size 0x200 /** * The file flags and the date and time fields are in the same format as the one used in the FAT file system. diff --git a/xtaf/xtaf_endian.h b/xtaf/xtaf_endian.h index 935c7fb..4918b7d 100644 --- a/xtaf/xtaf_endian.h +++ b/xtaf/xtaf_endian.h @@ -51,6 +51,14 @@ static inline uint32_t host2be32(uint32_t val) { #endif } +static inline uint32_t le32tohost(uint32_t val) { +#ifndef LITTLE_ENDIAN + return bswap32(val); +#else + return val; +#endif +} + static inline uint16_t host2be16(uint16_t val) { #ifdef LITTLE_ENDIAN return bswap32(val); diff --git a/xtaf/xtaf_partition.c b/xtaf/xtaf_partition.c index 6e3de8c..c1be0ed 100644 --- a/xtaf/xtaf_partition.c +++ b/xtaf/xtaf_partition.c @@ -177,6 +177,39 @@ int check_devkit_hdd(DISC_INTERFACE * disc) { return 1; } +/** return 1 if hdd has valid security sector, 0 if invalid. out_num_sectors populated with sector size **/ +int check_security_sector(DISC_INTERFACE * disc, unsigned int *out_num_sectors) { + int r = 0; + + if (out_num_sectors != NULL) + *out_num_sectors = 0; + + uint8_t *sectorBuffer = _XTAF_mem_allocate(XENON_DISK_SECTOR_SIZE); + if (sectorBuffer == NULL) + return 0; + + // read the security sector off the disk + if (!_XTAF_disc_readSectors(disc,0x10,1,sectorBuffer)) + goto end; + + // compare serial, firmware and revision of the drive to the security sector + struct _x_hdd_security_sector_s *security_sector = (struct _x_hdd_security_sector_s *)sectorBuffer; + if (memcmp(security_sector->serial_number, ata.serial, sizeof(security_sector->serial_number)) != 0) + goto end; + if (memcmp(security_sector->firmware_revision, ata.rev, sizeof(security_sector->firmware_revision)) != 0) + goto end; + if (memcmp(security_sector->model_number, ata.model, sizeof(security_sector->model_number)) != 0) + goto end; + + r = 1; + if (out_num_sectors != NULL) + *out_num_sectors = le32tohost(security_sector->number_of_sector); + +end: + _XTAF_mem_free(sectorBuffer); + return r; +} + xtaf_partition_private * xtaf_mount(void * disc, uint32_t start_sector, uint32_t num_sectors, uint32_t cacheSize, uint32_t sectorsPerPage, uint8_t *sectorBuffer ) { bool err; static int partition_nbr = 0; @@ -270,8 +303,11 @@ int xtaf_init(struct xtaf_context *ctx, DISC_INTERFACE * disc) { if (check_devkit_hdd(disc) == 1) xprintf("DEVKIT HDD detected!\r\n"); - - uint8_t *sectorBuffer = (uint8_t*) _XTAF_mem_allocate(XENON_DISK_SECTOR_SIZE); + + unsigned int real_disk_sector_count = 0; + check_security_sector(disc, &real_disk_sector_count); + + uint8_t *sectorBuffer = (uint8_t*) _XTAF_mem_allocate(XENON_DISK_SECTOR_SIZE); int found = 0; @@ -287,6 +323,25 @@ int xtaf_init(struct xtaf_context *ctx, DISC_INTERFACE * disc) { //num_sectors = (uint32_t) (312581808) - start_sector; extern struct xenon_ata_device ata; num_sectors = (uint32_t) (ata.size) - start_sector; + if (real_disk_sector_count > 0) + { + // Restrict the number of sectors used for the data partition to what the MS security sector says. + // This matches the behaviour of the official OS. There is a problem here, though... + // + // If a drive has a legitimate security sector, and the drive's true ending LBA is greater than what is specified, + // (e.g. an SSD that has been flashed with a fake model/serial, and a real drive's secruity sector written to it) + // then pre-Sep2026 xebuild patches and pre-Sep2026 libxtaf will see a completely different FAT from the drive + // compared to retail consoles, or post-Sep2026 xebuild patches/libxtaf. + // + // We're going to assume that, since if a security sector exists you want to use the drive on a retail console, + // that we should read the partition as if it is a retail console and use the same XTAF extents. + // There are no good solutions here, but I think using the retail OS behaviour is the most well-intentioned solution. + if (real_disk_sector_count < ata.size) + { + printf("XTAF sector count mismatch! (0x%x->0x%x)\n", ata.size, real_disk_sector_count); + } + num_sectors = real_disk_sector_count - start_sector; + } #else num_sectors = (20003880960 / XENON_DISK_SECTOR_SIZE) - start_sector; // hdd_dump file size #endif