24#include "hdsk-devctl.h"
28#ifdef HDSK_SUPPORT_HDLFS
33IRX_ID(
"hdsk", APA_MODVER_MAJOR, APA_MODVER_MINOR);
41static int hdskEventFlagID;
42static int hdskThreadID;
43static int hdskStopFlag;
45static u32 hdskProgress;
47u8 IOBuffer[IOBUFFER_SIZE_SECTORS * 512];
49#define HDSK_MIN_PART_SIZE 0x00040000
51static int hdskRemoveTmp(
int device)
58 clink = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &result);
62 while (clink != NULL) {
64 if (!memcmp(clink->header->id,
partition,
sizeof(clink->header->id))) {
69 clink = apaGetNextHeader(clink, &result);
72 if (result == 0 && clink != NULL) {
75 APA_PRINTF(
"remove _tmp\n");
76 sub = clink->header->nsub;
77 clink->header->nsub = 0;
79 clink->flags |= APA_CACHE_FLAG_DIRTY;
80 start = clink->header->start + 0x2000;
81 apaCacheFlushAllDirty(device);
83 for (--sub; sub != -1; sub--) {
86 if ((clinkSub = apaCacheGetHeader(device, clink->header->subs[sub].start, APA_IO_MODE_READ, &result)) != NULL) {
87 if ((result = apaDelete(clinkSub)) != 0) {
94 clink = apaCacheAlloc();
96 sceAtaDmaTransfer(device, clink->header, start, 2, ATA_DIR_WRITE);
103static apa_cache_t *hdskFindEmptyPartition(
int device, u32 size)
108 clink = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &result);
109 while (clink != NULL) {
110 if (clink->header->length != size || clink->header->type != APA_TYPE_FREE) {
111 clink = apaGetNextHeader(clink, &result);
122 APA_PRINTF(
"found empty partition at %08lx, size %08lx.\n", clink->header->start, clink->header->length);
128static int hdskIsPartitionOfSize(
int device, u32 sector, u32 size)
131 int result, returnValue;
134 if ((clink = apaCacheGetHeader(device, sector, APA_IO_MODE_READ, &result)) != NULL) {
135 if (clink->header->type == APA_TYPE_FREE) {
136 returnValue = 0 < (clink->header->length ^ size);
145static u32 hdskGetPartitionPrev(
int device, u32 size, u32 start)
153 if ((clink = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &result)) != NULL) {
155 return (clink->header->prev);
161static apa_cache_t *hdskFindLastUsedPartition(
int device, u32 size, u32 start,
int mode)
168 previous = hdskGetPartitionPrev(device, size, start);
169 DoubleSize = size * 2;
170 while (start < previous) {
171 if ((clink = apaCacheGetHeader(device, previous, APA_IO_MODE_READ, &result)) != NULL) {
172 if (clink->header->length == size && clink->header->type != APA_TYPE_FREE) {
174 if (clink->header->start % DoubleSize == 0) {
175 if ((
partition = clink->header->next) == 0) {
182 if (!hdskIsPartitionOfSize(device,
partition, size)) {
193 previous = clink->header->prev;
203 APA_PRINTF(
"found last used partition at %08lx, size %08lx.\n", clink->header->start, clink->header->length);
209static int hdskFindPartitionOfSize(
int device,
apa_header_t *start, u32 MinSize,
int mode)
217 BlockSize = start->length;
218 while (BlockSize < MinSize && next != 0) {
219 if ((clink = apaCacheGetHeader(device, next, APA_IO_MODE_READ, &result)) != NULL) {
220 if (clink->header->type == APA_TYPE_FREE) {
224 next = clink->header->next;
225 BlockSize += clink->header->length;
232 if (BlockSize == MinSize) {
234 if (start->start % (MinSize * 2) != 0) {
235 return ((hdskIsPartitionOfSize(device, start->prev, MinSize) != 0) ? 0 : 1);
238 return ((hdskIsPartitionOfSize(device, next, MinSize) != 0) ? 0 : 1);
249static apa_cache_t *hdskFindLastUsedBlock(
int device, u32 MinSize, u32 start,
int mode)
253 u32 NextStart, sector;
257 if ((NextStart = hdskGetPartitionPrev(device, MinSize, start)) != 0) {
258 while (sector < NextStart) {
259 if ((last = apaCacheGetHeader(device, NextStart, 0, &result)) != NULL) {
260 if (last->header->start % MinSize != 0) {
261 if (last->header->length < MinSize && last->header->type != APA_TYPE_FREE) {
262 if (hdskFindPartitionOfSize(device, last->header, MinSize, mode) != 0) {
269 NextStart = last->header->prev;
281 APA_PRINTF(
"found last used block of partitions at %08lx, size %08lx.\n", last->header->start, last->header->length);
292 blocks = dest->length / IOBUFFER_SIZE_SECTORS;
293 APA_PRINTF(
"copy start...");
296 result = sceAtaDmaTransfer(device, IOBuffer, start->start + 2, IOBUFFER_SIZE_SECTORS - 2, ATA_DIR_READ) == 0 ? 0 : -
EIO;
299 result = sceAtaDmaTransfer(device, IOBuffer, dest->start + 2, IOBUFFER_SIZE_SECTORS - 2, ATA_DIR_WRITE) == 0 ? 0 : -
EIO;
302 hdskProgress += IOBUFFER_SIZE_SECTORS;
304 for (i = 1; i < blocks; i++) {
305 result = sceAtaDmaTransfer(device, IOBuffer, start->start + i * IOBUFFER_SIZE_SECTORS, IOBUFFER_SIZE_SECTORS, ATA_DIR_READ) == 0 ? 0 : -
EIO;
308 result = sceAtaDmaTransfer(device, IOBuffer, dest->start + i * IOBUFFER_SIZE_SECTORS, IOBUFFER_SIZE_SECTORS, ATA_DIR_WRITE) == 0 ? 0 : -
EIO;
311 hdskProgress += IOBUFFER_SIZE_SECTORS;
316 APA_PRINTF(
"error: write failed at %08lx.\n", dest->start + i * IOBUFFER_SIZE_SECTORS);
320 APA_PRINTF(
"error: read failed at %08lx.\n", start->start + i * IOBUFFER_SIZE_SECTORS);
336 u32 StartSector, next, prev;
338 StartSector = dest->header->start;
339 next = dest->header->next;
340 prev = dest->header->prev;
342 APA_PRINTF(
"swap %s partition start...", (start->header->flags &
APA_FLAG_SUB) ?
"sub" :
"main");
344 memcpy(dest->header, start->header,
sizeof(
apa_header_t));
345 dest->header->start = StartSector;
346 dest->header->next = next;
347 dest->header->prev = prev;
348 StartSector = start->header->start;
349 next = start->header->next;
350 prev = start->header->prev;
353 start->header->magic = APA_MAGIC;
354 start->header->start = StartSector;
355 start->header->next = next;
356 start->header->prev = prev;
357 start->header->length = dest->header->length;
358 start->header->modver = APA_MODVER;
359 start->header->type = dest->header->type;
360 strcpy(start->header->id,
"_tmp");
362 memset(clink, 0,
sizeof(clink));
364 if ((clink[0] = apaCacheGetHeader(device, dest->header->main, APA_IO_MODE_READ, &result)) != NULL) {
365 for (i = 0; (u32)i < clink[0]->header->nsub; i++) {
366 if (start->header->start == clink[0]->header->subs[i].start) {
367 clink[0]->header->subs[i].start = dest->header->start;
368 clink[0]->flags |= APA_CACHE_FLAG_DIRTY;
369#ifdef HDSK_SUPPORT_HDLFS
370 if (dest->header->type == APA_TYPE_HDLFS) {
371 hdlUpdateGameSliceInfo(device, dest->header->main, i, start->header->start, dest->header->start);
378 if ((u32)i == clink[0]->header->nsub) {
379 apaCacheFree(clink[0]);
387 for (i = 0; (u32)i < dest->header->nsub; i++) {
388 if ((clink[i] = apaCacheGetHeader(device, dest->header->subs[i].start, APA_IO_MODE_READ, &result)) == NULL) {
389 for (--i; i >= 0; i--) {
390 apaCacheFree(clink[i]);
397 for (i = 0; (u32)i < dest->header->nsub; i++) {
398 clink[i]->header->main = dest->header->start;
399 clink[i]->flags |= APA_CACHE_FLAG_DIRTY;
402#ifdef HDSK_SUPPORT_HDLFS
403 if (dest->header->type == APA_TYPE_HDLFS) {
404 hdlUpdateGameSliceInfo(device, dest->header->start, 0, start->header->start, dest->header->start);
409 dest->flags |= APA_CACHE_FLAG_DIRTY;
410 start->flags |= APA_CACHE_FLAG_DIRTY;
411 apaCacheFlushAllDirty(device);
412 for (i = 0; i < 64; i++) {
413 if (clink[i] != NULL) {
414 apaCacheFree(clink[i]);
427 APA_PRINTF(
"MovePartition: %08lx to %08lx. sector count = %08lx.\n", start->header->start, dest->header->start, start->header->length);
429 if (dest->header->type != APA_TYPE_FREE) {
430 APA_PRINTF(
"error: destination is not empty.\n");
434 if (dest->header->length != start->header->length) {
435 APA_PRINTF(
"error: source and destination size are not same.\n");
439 if ((result = hdskRemoveTmp(device)) == 0) {
440 if ((result = CopyPartition(device, dest->header, start->header)) == 0) {
441 if (hdskStopFlag == 0) {
442 SwapPartition(device, dest, start);
447 APA_PRINTF(
"MovePartition: done\n");
459 APA_PRINTF(
"split empty partition.\n");
461 while (
partition->header->length != length) {
464 if ((empty = apaCacheGetHeader(device,
partition->header->next, APA_IO_MODE_READ, &result)) != NULL) {
468 partition->header->next = clink->header->start;
469 partition->flags |= APA_CACHE_FLAG_DIRTY;
471 empty->header->prev = clink->header->start;
472 empty->flags |= APA_CACHE_FLAG_DIRTY;
473 apaCacheFlushAllDirty(device);
488 remaining = dest->header->length;
489 APA_PRINTF(
"MovePartitionsBlock: %08lx to %08lx. sector count = %08lx.\n", start->header->start, dest->header->start, dest->header->length);
492 if ((result = SplitEmptyPartition(device, dest, start->header->length)) == 0) {
493 if ((result = MovePartition(device, dest, start)) == 0) {
494 remaining -= dest->header->length;
495 if (hdskStopFlag == 0 && remaining != 0) {
497 if ((dest = apaGetNextHeader(dest, &stat)) == NULL || (start = apaGetNextHeader(start, &stat)) == NULL) {
514 APA_PRINTF(
"MovePartitionsBlock: done\n");
519static void HdskThread(
int device)
528 if ((hdskStatus = hdskRemoveTmp(device)) >= 0) {
529 for (PartSize = HDSK_MIN_PART_SIZE; PartSize <
HddInfo[device].partitionMaxSize; PartSize *= 2) {
530 while ((hdskStatus = hdskRemoveTmp(device)) >= 0) {
531 if ((clink = hdskFindEmptyPartition(device, PartSize)) != NULL) {
532 if ((clink2 = hdskFindLastUsedPartition(device, PartSize, clink->header->start, 1)) == NULL) {
533 if ((HDSK_MIN_PART_SIZE < PartSize) && (clink2 = hdskFindLastUsedBlock(device, PartSize, clink->header->start, 1)) != NULL) {
534 goto move_partition_block;
538 if ((clink2 = hdskFindLastUsedPartition(device, PartSize, clink->header->start, 0)) == NULL) {
540 if (HDSK_MIN_PART_SIZE < PartSize) {
541 if ((clink2 = hdskFindLastUsedBlock(device, PartSize, clink->header->start, 0)) != NULL) {
542 goto move_partition_block;
546 APA_PRINTF(
"there is no copyable partition/partitions block.\n");
553 move_partition_block:
555 if ((hdskStatus = MovePartitionsBlock(device, clink, clink2)) != 0) {
556 goto hdsk_thread_end;
561 hdskStatus = MovePartition(device, clink, clink2);
563 apaCacheFree(clink2);
564 if (hdskStatus != 0) {
566 goto hdsk_thread_end;
577 if (hdskStatus != 0 || hdskStopFlag != 0) {
584 hdskRemoveTmp(device);
585 SetEventFlag(hdskEventFlagID, 1);
599static int hdskBitmapInit(
int device)
604 clink = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &result);
610 for (BitmapUsed = 0; clink != NULL;) {
614 pBitmap->start = clink->header->start;
615 pBitmap->length = clink->header->length;
616 pBitmap->type = clink->header->type;
621 clink = apaGetNextHeader(clink, &result);
635 PartSize = HDSK_MIN_PART_SIZE;
636 if ((result = hdskBitmapInit(device)) == 0) {
639 hdskSimGetFreeSectors(device, buf, deviceInfo);
641 for (pDeviceInfo = &deviceInfo[device]; PartSize < pDeviceInfo->partitionMaxSize; PartSize *= 2) {
645 IsValidPartSize = HDSK_MIN_PART_SIZE < PartSize;
647 while ((pPartBitmap = hdskSimFindEmptyPartition(PartSize)) != NULL) {
650 if (((pSelEmptyPartBM = hdskSimFindLastUsedPartition(PartSize, pPartBitmap->start, 1)) == NULL) &&
651 (!IsValidPartSize || (pSelEmptyPartBM = hdskSimFindLastUsedBlock(PartSize, pPartBitmap->start, 1)) == NULL) &&
652 ((pSelEmptyPartBM = hdskSimFindLastUsedPartition(PartSize, pPartBitmap->start, 0)) == NULL)) {
653 if (IsValidPartSize && (pSelEmptyPartBM = hdskSimFindLastUsedBlock(PartSize, pPartBitmap->start, 0)) != NULL) {
654 APA_PRINTF(
"found last used block of partitions at %08lx, size %08lx.\n", pSelEmptyPartBM->start, pSelEmptyPartBM->length);
655 hdskSimMovePartitionsBlock(pPartBitmap, pSelEmptyPartBM);
657 APA_PRINTF(
"there is no copyable partition/partitions block.\n");
661 APA_PRINTF(
"found last used partition at %08lx, size %08lx.\n", pSelEmptyPartBM->start, pSelEmptyPartBM->length);
662 hdskSimMovePartition(pPartBitmap, pSelEmptyPartBM);
668 hdskSimGetFreeSectors(device, buf, deviceInfo);
669 printf(
"copy total %08lx sectors\n", TotalCopied);
670 buf->total = TotalCopied;
676static int HdskDevctl(
iomanX_iop_file_t *fd,
const char *name,
int cmd,
void *arg,
unsigned int arglen,
void *buf,
unsigned int buflen)
686 if (
HddInfo[fd->unit].status != 0) {
691 case HDSK_DEVCTL_GET_FREE:
692 result = apaGetFreeSectors(fd->unit, buf,
HddInfo);
694 case HDSK_DEVCTL_GET_HDD_STAT:
695 if ((result = hdskRemoveTmp(fd->unit)) == 0)
696 result = hdskGetStat(fd->unit, buf,
HddInfo);
698 case HDSK_DEVCTL_START:
699 result = StartThread(hdskThreadID, (
void *)(uiptr)fd->unit);
701 case HDSK_DEVCTL_WAIT:
702 result = WaitEventFlag(hdskEventFlagID, 1, WEF_CLEAR | WEF_OR, &bits);
704 case HDSK_DEVCTL_POLL:
705 result = PollEventFlag(hdskEventFlagID, 1, WEF_CLEAR | WEF_OR, &bits);
706 if (result == KE_EVF_COND)
709 case HDSK_DEVCTL_GET_STATUS:
712 case HDSK_DEVCTL_STOP:
716 case HDSK_DEVCTL_GET_PROGRESS:
717 result = (int)hdskProgress;
726IOMANX_RETURN_VALUE_IMPL(0);
727IOMANX_RETURN_VALUE_IMPL(
EPERM);
731 IOMANX_RETURN_VALUE(0),
732 IOMANX_RETURN_VALUE(
EPERM),
733 IOMANX_RETURN_VALUE(
EPERM),
734 IOMANX_RETURN_VALUE(
EPERM),
735 IOMANX_RETURN_VALUE(
EPERM),
736 IOMANX_RETURN_VALUE(
EPERM),
737 IOMANX_RETURN_VALUE(
EPERM),
738 IOMANX_RETURN_VALUE(
EPERM),
739 IOMANX_RETURN_VALUE(
EPERM),
740 IOMANX_RETURN_VALUE(
EPERM),
741 IOMANX_RETURN_VALUE(
EPERM),
742 IOMANX_RETURN_VALUE(
EPERM),
743 IOMANX_RETURN_VALUE(
EPERM),
744 IOMANX_RETURN_VALUE(
EPERM),
745 IOMANX_RETURN_VALUE(
EPERM),
746 IOMANX_RETURN_VALUE(
EPERM),
747 IOMANX_RETURN_VALUE(
EPERM),
748 IOMANX_RETURN_VALUE(
EPERM),
749 IOMANX_RETURN_VALUE(
EPERM),
750 IOMANX_RETURN_VALUE(
EPERM),
751 IOMANX_RETURN_VALUE(
EPERM),
752 IOMANX_RETURN_VALUE_S64(
EPERM),
754 IOMANX_RETURN_VALUE(
EPERM),
755 IOMANX_RETURN_VALUE(
EPERM),
756 IOMANX_RETURN_VALUE(
EPERM),
766int APA_ENTRYPOINT(
int argc,
char **argv)
775 if (apaGetTime(&time) != 0) {
776 APA_PRINTF(
"error: could not get date\n");
777 return MODULE_NO_RESIDENT_END;
780 APA_PRINTF(
"%02d:%02d:%02d %02d/%02d/%d\n", time.hour, time.min, time.sec, time.month, time.day, time.year);
782 for (i = 0; i < 2; i++) {
783 if ((pDevInfo = sceAtaInit(i)) == NULL) {
784 APA_PRINTF(
"error: ata initialization failed.\n");
785 return MODULE_NO_RESIDENT_END;
793 if (HdskUnlockHdd(i) == 0) {
797 APA_PRINTF(
"disk%d: 0x%08lx sectors, max 0x%08lx\n", i,
HddInfo[i].totalLBA,
HddInfo[i].partitionMaxSize);
803 for (i = 0; i < 2; i++) {
805 if (apaJournalRestore(i) != 0) {
806 return MODULE_NO_RESIDENT_END;
809 if (apaGetFormat(i, &
HddInfo[i].format)) {
815 if ((hdskEventFlagID = HdskCreateEventFlag()) < 0) {
816 return MODULE_NO_RESIDENT_END;
819 if ((hdskThreadID = HdskCreateThread((
void *)&HdskThread, 0x2080)) < 0) {
820 return MODULE_NO_RESIDENT_END;
823 iomanX_DelDrv(HdskDevice.name);
824 if (iomanX_AddDrv(&HdskDevice) == 0) {
825 APA_PRINTF(
"driver start.\n");
826 return MODULE_RESIDENT_END;
829 return MODULE_NO_RESIDENT_END;