PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
apa.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9#
10# Main APA related routines
11*/
12
13#include <errno.h>
14#include <iomanX.h>
15#ifdef _IOP
16#include <sysclib.h>
17#else
18#include <string.h>
19#endif
20#include <stdio.h>
21#ifdef APA_USE_ATAD
22#include <atad.h>
23#endif
24#include <hdd-ioctl.h>
25
26#include "libapa.h"
27#include "hdd_blkio.h"
28
29#ifdef APA_SUPPORT_BHDD
30extern apa_device_t hddDevices[];
31#endif
32
33const char apaMBRMagic[] = "Sony Computer Entertainment Inc.";
34
35void apaSaveError(s32 device, void *buffer, u32 lba, u32 err_lba)
36{
37 memset(buffer, 0, 512);
38 *(u32 *)buffer = err_lba;
39 blkIoDmaTransfer(device, buffer, lba, 1, BLKIO_DIR_WRITE);
40 blkIoFlushCache(device);
41}
42
43void apaSetPartErrorSector(s32 device, u32 lba)
44{ // used to set the lba of a partition that has a error...
45 apa_cache_t *clink;
46 clink = apaCacheAlloc();
47 apaSaveError(device, clink->header, APA_SECTOR_PART_ERROR, lba);
48 apaCacheFree(clink);
49}
50
51int apaGetPartErrorSector(s32 device, u32 lba, u32 *lba_out)
52{
53 apa_cache_t *clink;
54 int rv = 0;
55
56 if (!(clink = apaCacheAlloc()))
57 return -ENOMEM;
58
59 if (blkIoDmaTransfer(device, clink->header, lba, 1, BLKIO_DIR_READ))
60 return -EIO;
61
62 if (lba_out)
63 *lba_out = *clink->error_lba;
64 if (*clink->error_lba)
65 rv = 1; // error is set ;)
66 apaCacheFree(clink);
67 return rv;
68}
69
70int apaGetPartErrorName(s32 device, char *name)
71{
72 u32 lba;
73 int rv = 0;
74 apa_cache_t *clink;
75
76 if ((rv = apaGetPartErrorSector(device, APA_SECTOR_PART_ERROR, &lba)) <= 0)
77 return rv;
78 if (!(clink = apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, &rv)))
79 return rv;
80
81 while (clink) {
82 if (clink->header->type != APA_TYPE_FREE &&
83 !(clink->header->flags & APA_CACHE_FLAG_DIRTY) &&
84 clink->header->start == lba) {
85 if (name) {
86 strncpy(name, clink->header->id, APA_IDMAX - 1);
87 name[APA_IDMAX - 1] = '\0';
88 }
89 apaCacheFree(clink);
90 return 1;
91 }
92 clink = apaGetNextHeader(clink, &rv);
93 }
94
95 // clear error if no errors and partitions was not found...
96 if (rv == 0)
97 apaSetPartErrorSector(device, 0);
98 return rv;
99}
100
101apa_cache_t *apaFillHeader(s32 device, const apa_params_t *params, u32 start, u32 next,
102 u32 prev, u32 length, int *err)
103{ // used for making a new partition
104 apa_cache_t *clink;
105
106 if (!(clink = apaCacheGetHeader(device, start, APA_IO_MODE_WRITE, err)))
107 return NULL;
108 memset(clink->header, 0, sizeof(apa_header_t));
109 clink->header->magic = APA_MAGIC;
110 clink->header->start = start;
111 clink->header->next = next;
112 clink->header->prev = prev;
113 clink->header->length = length;
114 clink->header->type = params->type;
115 clink->header->flags = params->flags;
116 clink->header->modver = APA_MODVER;
117 memcpy(clink->header->id, params->id, APA_IDMAX);
118 if (params->flags & APA_FLAG_SUB) {
119 clink->header->main = params->main;
120 clink->header->number = params->number;
121 } else {
122 if (strncmp(clink->header->id, "_tmp", APA_IDMAX) != 0) {
123 memcpy(clink->header->rpwd, params->rpwd, APA_PASSMAX);
124 memcpy(clink->header->fpwd, params->fpwd, APA_PASSMAX);
125 }
126 }
127 apaGetTime(&clink->header->created);
128 clink->flags |= APA_CACHE_FLAG_DIRTY;
129 return clink;
130}
131
132apa_cache_t *apaInsertPartition(s32 device, const apa_params_t *params, u32 sector, int *err)
133{ // Adds a new partition using an empty block.
134 apa_cache_t *clink_empty;
135 apa_cache_t *clink_this;
136
137 if ((clink_this = apaCacheGetHeader(device, sector, APA_IO_MODE_READ, err)) == 0)
138 return 0;
139
140 while (clink_this->header->length != params->size) {
141 apa_cache_t *clink_next;
142
143 if ((clink_next = apaCacheGetHeader(device, clink_this->header->next, APA_IO_MODE_READ, err)) == NULL) { // Get next partition
144 apaCacheFree(clink_this);
145 return 0;
146 }
147 clink_this->header->length >>= 1;
148 clink_empty = apaRemovePartition(device, (clink_this->header->start + clink_this->header->length),
149 clink_this->header->next, clink_this->header->start, clink_this->header->length);
150 clink_this->header->next = clink_empty->header->start;
151 clink_this->flags |= APA_CACHE_FLAG_DIRTY;
152 clink_next->header->prev = clink_empty->header->start;
153 clink_next->flags |= APA_CACHE_FLAG_DIRTY;
154
155 apaCacheFlushAllDirty(device);
156 apaCacheFree(clink_empty);
157 apaCacheFree(clink_next);
158 }
159 apaCacheFree(clink_this);
160 clink_this = apaFillHeader(device, params, clink_this->header->start, clink_this->header->next,
161 clink_this->header->prev, params->size, err);
162 apaCacheFlushAllDirty(device);
163 return clink_this;
164}
165
166apa_cache_t *apaFindPartition(s32 device, const char *id, int *err)
167{
168 apa_cache_t *clink;
169 u32 sector = 0;
170
171#ifdef APA_SUPPORT_BHDD
172 if (strcmp(id, "__xcontents") == 0 || strcmp(id, "__extend") == 0 || strcmp(id, "__xdata") == 0)
173 sector = hddDevices[device].totalLBA;
174#endif
175
176 clink = apaCacheGetHeader(device, sector, APA_IO_MODE_READ, err);
177 while (clink) {
178 if (!(clink->header->flags & APA_FLAG_SUB)) {
179 if (memcmp(clink->header->id, id, APA_IDMAX) == 0)
180 return clink; // found
181 }
182 clink = apaGetNextHeader(clink, (int *)err);
183 }
184 if (*err == 0) {
185 *err = -ENOENT;
186 return NULL;
187 // return (apa_cache_t *)-ENOENT; // <-- BUG code tests for NULL only
188 }
189 *err = 0;
190 return NULL;
191}
192
193void apaAddEmptyBlock(apa_header_t *header, u32 *emptyBlocks)
194{ // small helper.... to track empty blocks..
195 u32 i;
196
197 if (header->type == APA_TYPE_FREE) {
198 for (i = 0; i < 32; i++) {
199 if (header->length == (u32)(((u32)1) << i)) {
200 if (emptyBlocks[i] == APA_TYPE_FREE) {
201 emptyBlocks[i] = header->start;
202 return;
203 }
204 }
205 }
206 }
207}
208
209apa_cache_t *apaRemovePartition(s32 device, u32 start, u32 next, u32 prev,
210 u32 length)
211{
212 apa_cache_t *clink;
213 int err;
214
215 if ((clink = apaCacheGetHeader(device, start, APA_IO_MODE_WRITE, &err)) == NULL)
216 return NULL;
217 memset(clink->header, 0, sizeof(apa_header_t));
218 clink->header->magic = APA_MAGIC;
219 clink->header->start = start;
220 clink->header->next = next;
221 clink->header->prev = prev;
222 clink->header->length = length;
223 strcpy(clink->header->id, "__empty");
224 apaGetTime(&clink->header->created);
225 clink->flags |= APA_CACHE_FLAG_DIRTY;
226 return clink;
227}
228
229void apaMakeEmpty(apa_cache_t *clink)
230{
231 u32 saved_start;
232 u32 saved_next;
233 u32 saved_prev;
234 u32 saved_length;
235
236 saved_start = clink->header->start;
237 saved_next = clink->header->next;
238 saved_prev = clink->header->prev;
239 saved_length = clink->header->length;
240 memset(clink->header, 0, sizeof(apa_header_t));
241 clink->header->magic = APA_MAGIC;
242 clink->header->start = saved_start;
243 clink->header->next = saved_next;
244 clink->header->prev = saved_prev;
245 clink->header->length = saved_length;
246 apaGetTime(&clink->header->created);
247 strcpy(clink->header->id, "__empty");
248 clink->flags |= APA_CACHE_FLAG_DIRTY;
249}
250
251apa_cache_t *apaDeleteFixPrev(apa_cache_t *clink, int *err)
252{
253 apa_cache_t *clink2 = clink;
254 apa_header_t *header = clink2->header;
255 u32 device = clink->device;
256 u32 length = clink->header->length;
257 u32 saved_next = clink->header->next;
258 u32 saved_length = clink->header->length;
259 u32 tmp;
260
261 while (header->start) {
262 if (!(clink2 = apaCacheGetHeader(device, header->prev, APA_IO_MODE_READ, err))) {
263 apaCacheFree(clink);
264 return NULL;
265 }
266 header = clink2->header;
267 tmp = header->length + length;
268 if (header->type != 0) {
269 apaCacheFree(clink2);
270 break;
271 }
272 if ((header->start % tmp) || (tmp & (tmp - 1))) {
273 apaCacheFree(clink2);
274 break;
275 }
276 length = tmp;
277 apaCacheFree(clink);
278 clink = clink2;
279 }
280 if (length != saved_length) {
281 if (!(clink2 = apaCacheGetHeader(device, saved_next, APA_IO_MODE_READ, err))) {
282 apaCacheFree(clink);
283 return NULL;
284 }
285 clink->header->length = length;
286 clink->header->next = clink->header->start + length;
287 clink2->header->prev = clink->header->start;
288 clink2->flags |= APA_CACHE_FLAG_DIRTY;
289 clink->flags |= APA_CACHE_FLAG_DIRTY;
290 apaCacheFlushAllDirty(device);
291 apaCacheFree(clink2);
292 }
293 return clink;
294}
295
296
297apa_cache_t *apaDeleteFixNext(apa_cache_t *clink, int *err)
298{
299 apa_header_t *header = clink->header;
300 u32 length = header->length;
301 u32 saved_length = header->length;
302 u32 lnext = header->next;
303 u32 device = clink->device;
304 u32 tmp;
305
306 while (lnext != 0) {
307 apa_cache_t *clink1;
308
309 if (!(clink1 = apaCacheGetHeader(device, lnext, APA_IO_MODE_READ, err))) {
310 apaCacheFree(clink);
311 return 0;
312 }
313 header = clink1->header;
314 tmp = header->length + length;
315 if (header->type != 0) {
316 apaCacheFree(clink1);
317 break;
318 }
319 if ((clink->header->start % tmp) != 0 || ((tmp - 1) & tmp)) {
320 apaCacheFree(clink1);
321 break;
322 }
323 length = tmp;
324 apaCacheFree(clink1);
325 lnext = header->next;
326 }
327 if (length != saved_length) {
328 apa_cache_t *clink2;
329
330 if (!(clink2 = apaCacheGetHeader(device, lnext, APA_IO_MODE_READ, err))) {
331 apaCacheFree(clink);
332 return NULL;
333 }
334 clink->header->length = length;
335 clink->header->next = lnext;
336 apaMakeEmpty(clink);
337 clink2->header->prev = clink->header->start;
338 clink2->flags |= APA_CACHE_FLAG_DIRTY;
339 apaCacheFlushAllDirty(device);
340 apaCacheFree(clink2);
341 }
342 return clink;
343}
344
345
346int apaDelete(apa_cache_t *clink)
347{
348 int rv = 0;
349 u32 device = clink->device;
350 u32 start = clink->header->start;
351
352 if (!start) {
353 apaCacheFree(clink);
354 return -EACCES;
355 }
356
357 if (clink->header->next == 0) {
358 apa_cache_t *clink_mbr;
359
360 if ((clink_mbr = apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, &rv)) == NULL) {
361 apaCacheFree(clink);
362 return rv;
363 }
364 do {
365 apaCacheFree(clink);
366 if ((clink = apaCacheGetHeader(clink->device, clink->header->prev, APA_IO_MODE_READ, &rv)) == NULL)
367 return 0;
368 clink->header->next = 0;
369 clink->flags |= APA_CACHE_FLAG_DIRTY;
370 clink_mbr->header->prev = clink->header->start;
371 clink_mbr->flags |= APA_CACHE_FLAG_DIRTY;
372 apaCacheFlushAllDirty(device);
373 } while (clink->header->type == 0);
374 apaCacheFree(clink_mbr);
375 } else {
376 int i;
377 u32 length = clink->header->length;
378
379 for (i = 0; i < 2; i++) {
380 if ((clink = apaDeleteFixPrev(clink, &rv)) == NULL)
381 return 0;
382 if ((clink = apaDeleteFixNext(clink, &rv)) == NULL)
383 return 0;
384 }
385 if (clink->header->start == start && clink->header->length == length) {
386 apaMakeEmpty(clink);
387 apaCacheFlushAllDirty(clink->device);
388 }
389 }
390 apaCacheFree(clink);
391 return rv;
392}
393
394int apaCheckSum(apa_header_t *header, int fullcheck)
395{
396 u32 *ptr = (u32 *)header;
397 u32 sum, i;
398
399 for (sum = 0, i = 1; i < 256; i++) // sizeof(header)/4 = 256, start at offset +4 to omit the checksum field.
400 sum += ptr[i];
401#ifdef APA_SUPPORT_GPT
402 if (!(fullcheck))
403 for (sum = 0, i = 1; i < 128; i++) // recalculate checksum only for first sector.
404 sum += ptr[i];
405#else
406 (void)fullcheck;
407#endif
408 return sum;
409}
410
411int apaReadHeader(s32 device, apa_header_t *header, u32 lba)
412{
413 if (blkIoDmaTransfer(device, header, lba, 2, BLKIO_DIR_READ) != 0)
414 return -EIO;
415 if (header->magic != APA_MAGIC)
416 return -EIO;
417#ifdef APA_SUPPORT_GPT
418 if ((u32)(apaCheckSum(header, 1)) != header->checksum)
419 if (lba == APA_SECTOR_MBR)
420 if ((u32)(apaCheckSum(header, 0)) != header->checksum)
421 return -EIO;
422#else
423 if ((u32)(apaCheckSum(header, 1)) != header->checksum)
424 return -EIO;
425#endif
426
427 if (lba == APA_SECTOR_MBR) {
428 if (strncmp(header->mbr.magic, apaMBRMagic, sizeof(header->mbr.magic)) == 0)
429 return 0;
430 APA_PRINTF(APA_DRV_NAME ": error: invalid partition table or version newer than I know.\n");
431 return -EIO;
432 }
433 return 0;
434}
435
436int apaWriteHeader(s32 device, apa_header_t *header, u32 lba)
437{
438 if (blkIoDmaTransfer(device, header, lba, 2, BLKIO_DIR_WRITE))
439 return -EIO;
440 return 0;
441}
442
443int apaGetFormat(s32 device, int *format)
444{
445 apa_cache_t *clink;
446 int rv = 0;
447 u32 i;
448
449 clink = apaCacheAlloc();
450 *format = 0;
451 if ((rv = apaReadHeader(device, clink->header, 0)) == 0) {
452 *format = clink->header->mbr.version;
453 if (blkIoDmaTransfer(device, clink->header, APA_SECTOR_SECTOR_ERROR, 2, BLKIO_DIR_READ))
454 rv = -EIO; // return -EIO;
455 if (rv == 0) {
456 u32 *pDW;
457
458 pDW = (u32 *)clink->header;
459 for (i = 0; i < 256; i++) {
460 if ((i & 0x7F) && pDW[i] != 0)
461 rv = 1;
462 }
463 }
464 }
465 apaCacheFree(clink);
466 return rv == 0;
467}
468
469u32 apaGetPartitionMax(u32 totalLBA)
470{
471 u32 i, size;
472
473#ifdef APA_WORKAROUND_LESS_THAN_40GB_CAPACITY
474 if (totalLBA < 0x04ffffff)
475 totalLBA = 0x04ffffff; // workaround for disks less then 40Gb
476#endif
477
478 totalLBA >>= 6; // totalLBA/64
479 size = (((u32)1) << 0x1F);
480 for (i = 31; i != 0; i--) {
481 size = ((u32)1) << i;
482 if (size & totalLBA)
483 break;
484 }
485 if (size < totalLBA)
486 i++;
487 return (1 << i);
488}
489
490apa_cache_t *apaGetNextHeader(apa_cache_t *clink, int *err)
491{
492 u32 start = clink->header->start;
493
494 apaCacheFree(clink);
495 if (!clink->header->next)
496 return NULL;
497
498 if (!(clink = apaCacheGetHeader(clink->device, clink->header->next, APA_IO_MODE_READ, err)))
499 return NULL;
500
501 if (start != clink->header->prev) {
502 APA_PRINTF(APA_DRV_NAME ": Warning: Invalid partition information. start != prev\n");
503 clink->header->prev = start;
504 clink->flags |= APA_CACHE_FLAG_DIRTY;
505 apaCacheFlushAllDirty(clink->device);
506 }
507 return clink;
508}
#define ENOENT
Definition errno.h:23
#define ENOMEM
Definition errno.h:43
#define EIO
Definition errno.h:29
#define EACCES
Definition errno.h:45
#define APA_FLAG_SUB
Definition hdd-ioctl.h:51