This commit is contained in:
averne 2020-06-06 19:30:19 +02:00
commit 73ce462b53
3 changed files with 157 additions and 37 deletions

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT([switch-tools],[1.6.0],[https://github.com/switchbrew/switch-tools/issues]) AC_INIT([switch-tools],[1.7.0],[https://github.com/switchbrew/switch-tools/issues])
AC_CONFIG_SRCDIR([src/build_pfs0.c]) AC_CONFIG_SRCDIR([src/build_pfs0.c])
AM_INIT_AUTOMAKE([subdir-objects]) AM_INIT_AUTOMAKE([subdir-objects])

View File

@ -132,10 +132,11 @@ int cJSON_GetBooleanOptional(const cJSON *obj, const char *field, int *out) {
fprintf(stderr, "Unknown boolean value in %s.\n", field); fprintf(stderr, "Unknown boolean value in %s.\n", field);
return 0; return 0;
} }
return 1;
} else { } else {
*out = 0; *out = 0;
return 0;
} }
return 1;
} }
int cJSON_GetU64(const cJSON *obj, const char *field, u64 *out) { int cJSON_GetU64(const cJSON *obj, const char *field, u64 *out) {
@ -219,6 +220,17 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
goto PARSE_CAPS_END; goto PARSE_CAPS_END;
} }
/* Parse use secure memory. */
/* This field is optional, and defaults to true (set before this function is called). */
int use_secure_memory = 1;
if (cJSON_GetBooleanOptional(npdm_json, "use_secure_memory", &use_secure_memory)) {
if (use_secure_memory) {
kip_hdr->Flags |= 0x20;
} else {
kip_hdr->Flags &= ~0x20;
}
}
/* Parse main_thread_stack_size. */ /* Parse main_thread_stack_size. */
u64 stack_size = 0; u64 stack_size = 0;
if (!cJSON_GetU64(npdm_json, "main_thread_stack_size", &stack_size)) { if (!cJSON_GetU64(npdm_json, "main_thread_stack_size", &stack_size)) {

View File

@ -19,9 +19,15 @@ typedef uint8_t u8;
/* FAC, FAH need to be tightly packed. */ /* FAC, FAH need to be tightly packed. */
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
u32 Version; u8 Version;
u8 CoiCount;
u8 SdoiCount;
u8 pad;
u64 Perms; u64 Perms;
u8 _0xC[0x20]; u64 CoiMin;
u64 CoiMax;
u64 SdoiMin;
u64 SdoiMax;
} FilesystemAccessControl; } FilesystemAccessControl;
#pragma pack(pop) #pragma pack(pop)
@ -29,10 +35,10 @@ typedef struct {
typedef struct { typedef struct {
u32 Version; u32 Version;
u64 Perms; u64 Perms;
u32 _0xC; u32 CoiOffset;
u32 _0x10; u32 CoiSize;
u32 _0x14; u32 SdoiOffset;
u32 _0x18; u32 SdoiSize;
} FilesystemAccessHeader; } FilesystemAccessHeader;
#pragma pack(pop) #pragma pack(pop)
@ -76,7 +82,8 @@ typedef struct {
u8 _0xD; u8 _0xD;
u8 MainThreadPriority; u8 MainThreadPriority;
u8 DefaultCpuId; u8 DefaultCpuId;
u64 _0x10; u32 _0x10;
u32 SystemResourceSize;
u32 ProcessCategory; u32 ProcessCategory;
u32 MainThreadStackSize; u32 MainThreadStackSize;
char Name[0x10]; char Name[0x10];
@ -219,6 +226,32 @@ int cJSON_GetU64(const cJSON *obj, const char *field, u64 *out) {
} }
} }
int cJSON_GetU32(const cJSON *obj, const char *field, u32 *out) {
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field);
if (cJSON_IsString(config) && (config->valuestring != NULL)) {
char *endptr = NULL;
*out = strtoul(config->valuestring, &endptr, 16);
if (config->valuestring == endptr) {
fprintf(stderr, "Failed to get %s (empty string)\n", field);
return 0;
} else if (errno == ERANGE) {
fprintf(stderr, "Failed to get %s (value out of range)\n", field);
return 0;
} else if (errno == EINVAL) {
fprintf(stderr, "Failed to get %s (not base16 string)\n", field);
return 0;
} else if (errno) {
fprintf(stderr, "Failed to get %s (unknown error)\n", field);
return 0;
} else {
return 1;
}
} else {
fprintf(stderr, "Failed to get %s (field not present).\n", field);
return 0;
}
}
int cJSON_GetU64FromObjectValue(const cJSON *config, u64 *out) { int cJSON_GetU64FromObjectValue(const cJSON *config, u64 *out) {
if (cJSON_IsString(config) && (config->valuestring != NULL)) { if (cJSON_IsString(config) && (config->valuestring != NULL)) {
char *endptr = NULL; char *endptr = NULL;
@ -257,6 +290,10 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
const cJSON *service = NULL; const cJSON *service = NULL;
const cJSON *services = NULL; const cJSON *services = NULL;
const cJSON *fsaccess = NULL; const cJSON *fsaccess = NULL;
const cJSON *cois = NULL;
const cJSON *coi = NULL;
const cJSON *sdois = NULL;
const cJSON *sdoi = NULL;
int status = 0; int status = 0;
cJSON *npdm_json = cJSON_Parse(json); cJSON *npdm_json = cJSON_Parse(json);
@ -305,6 +342,9 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
status = 0; status = 0;
goto NPDM_BUILD_END; goto NPDM_BUILD_END;
} }
cJSON_GetU32(npdm_json, "system_resource_size", &header.SystemResourceSize); // optional
if (!cJSON_GetU8(npdm_json, "process_category", (u8 *)&header.ProcessCategory)) { if (!cJSON_GetU8(npdm_json, "process_category", (u8 *)&header.ProcessCategory)) {
status = 0; status = 0;
goto NPDM_BUILD_END; goto NPDM_BUILD_END;
@ -370,18 +410,86 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
status = 0; status = 0;
goto NPDM_BUILD_END; goto NPDM_BUILD_END;
} }
cJSON_GetU64(fsaccess, "content_owner_id_min", &fac->CoiMin);
cJSON_GetU64(fsaccess, "content_owner_id_max", &fac->CoiMax);
cois = cJSON_GetObjectItemCaseSensitive(fsaccess, "content_owner_ids");
if (cJSON_IsArray(cois)) {
int idx = 0;
u64 *content_owner_id = (u64 *)((u8 *)fac + sizeof(FilesystemAccessControl));
cJSON_ArrayForEach(coi, cois) {
if (!cJSON_GetU64FromObjectValue(coi, content_owner_id)) {
status = 0;
goto NPDM_BUILD_END;
}
++content_owner_id;
++idx;
}
fac->CoiCount = idx;
}
cJSON_GetU64(fsaccess, "save_data_owner_id_min", &fac->SdoiMin);
cJSON_GetU64(fsaccess, "save_data_owner_id_max", &fac->SdoiMax);
sdois = cJSON_GetObjectItemCaseSensitive(fsaccess, "save_data_owner_ids");
if (cJSON_IsArray(sdois)) {
int idx = 0;
u64 *save_data_owner_id = (u64 *)((u8 *)fac + sizeof(FilesystemAccessControl) + fac->CoiCount * sizeof(u64));
cJSON_ArrayForEach(sdoi, sdois) {
if (!cJSON_GetU64FromObjectValue(sdoi, save_data_owner_id)) {
status = 0;
goto NPDM_BUILD_END;
}
++save_data_owner_id;
++idx;
}
fac->SdoiCount = idx;
}
acid->FacOffset = sizeof(NpdmAcid); acid->FacOffset = sizeof(NpdmAcid);
acid->FacSize = sizeof(FilesystemAccessControl); acid->FacSize = sizeof(FilesystemAccessControl) + fac->CoiCount * sizeof(u64) + fac->SdoiCount * sizeof(u64);
acid->SacOffset = (acid->FacOffset + acid->FacSize + 0xF) & ~0xF; acid->SacOffset = (acid->FacOffset + acid->FacSize + 0xF) & ~0xF;
/* Fah. */ /* Fah. */
FilesystemAccessHeader *fah = (FilesystemAccessHeader *)((u8 *)aci0 + sizeof(NpdmAci0)); FilesystemAccessHeader *fah = (FilesystemAccessHeader *)((u8 *)aci0 + sizeof(NpdmAci0));
fah->Version = 1; fah->Version = 1;
fah->Perms = fac->Perms; fah->Perms = fac->Perms;
fah->_0xC = 0x1C; fah->CoiOffset = sizeof(FilesystemAccessHeader);
fah->_0x14 = 0x1C; fah->CoiSize = fac->CoiCount ? 4 + fac->CoiCount * sizeof(u64) : 0;
fah->SdoiOffset = fah->CoiOffset + fah->CoiSize;
fah->SdoiSize = fac->SdoiCount ? 4 + fac->SdoiCount * sizeof(u64) : 0;
if (fac->CoiCount) {
u32 *count = (u32 *)((u8 *)fah + fah->CoiOffset);
*count = fac->CoiCount;
u64 *id = (u64 *)((u8 *)count + sizeof(u32));
cJSON_ArrayForEach(coi, cois) {
if (!cJSON_GetU64FromObjectValue(coi, id)) {
status = 0;
goto NPDM_BUILD_END;
}
++id;
}
}
if (fac->SdoiCount) {
u32 *count = (u32 *)((u8 *)fah + fah->SdoiOffset);
*count = fac->SdoiCount;
u64 *id = (u64 *)((u8 *)count + sizeof(u32));
cJSON_ArrayForEach(sdoi, sdois) {
if (!cJSON_GetU64FromObjectValue(sdoi, id)) {
status = 0;
goto NPDM_BUILD_END;
}
++id;
}
}
aci0->FahOffset = sizeof(NpdmAci0); aci0->FahOffset = sizeof(NpdmAci0);
aci0->FahSize = sizeof(FilesystemAccessHeader); aci0->FahSize = sizeof(FilesystemAccessHeader) + fah->CoiSize + fah->SdoiSize;
aci0->SacOffset = (aci0->FahOffset + aci0->FahSize + 0xF) & ~0xF; aci0->SacOffset = (aci0->FahOffset + aci0->FahSize + 0xF) & ~0xF;
/* Sac. */ /* Sac. */