Created
April 22, 2018 23:41
-
-
Save SciresM/8a2799069c960ac27b56b5051e799f90 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int cJSON_GetU8(const cJSON *obj, const char *field, u8 *out) { | |
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field); | |
if (cJSON_IsNumber(config)) { | |
*out = (u8)config->valueint; | |
return 1; | |
} else { | |
fprintf(stderr, "Failed to get %s (field not present).\n", field); | |
return 0; | |
} | |
} | |
int cJSON_GetU16(const cJSON *obj, const char *field, u16 *out) { | |
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field); | |
if (cJSON_IsNumber(config)) { | |
*out = (u16)config->valueint; | |
return 1; | |
} else { | |
fprintf(stderr, "Failed to get %s (field not present).\n", field); | |
return 0; | |
} | |
} | |
int cJSON_GetBoolean(const cJSON *obj, const char *field, int *out) { | |
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field); | |
if (cJSON_IsBool(config)) { | |
if (cJSON_IsTrue(config)) { | |
*out = 1; | |
} else if (cJSON_IsFalse(config) { | |
*out = 0; | |
} else { | |
fprintf(stderr, "Unknown boolean value in %s.\n", field); | |
return 0; | |
} | |
return 1; | |
} else { | |
fprintf(stderr, "Failed to get %s (field not present).\n", field); | |
return 0; | |
} | |
} | |
int cJSON_GetBooleanOptional(const cJSON *obj, const char *field, int *out) { | |
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field); | |
if (cJSON_IsBool(config)) { | |
if (cJSON_IsTrue(config)) { | |
*out = 1; | |
} else if (cJSON_IsFalse(config) { | |
*out = 0; | |
} else { | |
fprintf(stderr, "Unknown boolean value in %s.\n", field); | |
return 0; | |
} | |
} else { | |
*out = 0; | |
} | |
return 1; | |
} | |
int cJSON_GetU64(const cJSON *obj, const char *field, u64 *out) { | |
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field); | |
if (cJSON_IsString(title_id) && (title_id->valuestring != NULL)) { | |
char *endptr = NULL; | |
*out = strtoul(out, endptr, 16); | |
if (title_id->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 ParseKipConfiguration(const char *json, KipHeader *kip_hdr) { | |
const cJSON *capability = NULL; | |
const cJSON *capabilities = NULL; | |
int status = 0; | |
cJSON *npdm_json = cJSON_Parse(json); | |
if (npdm_json == NULL) { | |
const char *error_ptr = cJSON_GetErrorPtr(); | |
if (error_ptr != NULL) { | |
fprintf(stderr, "JSON Parse Error: %s\n", error_ptr); | |
} | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
/* Parse name. */ | |
title_name = cJSON_GetObjectItemCaseSensitive(npdm_json, "name"); | |
if (cJSON_IsString(title_name) && (title_name->valuestring != NULL)) { | |
strncpy(kip_hdr->Name, title_name->valuestring, sizeof(kip_hdr->Name)); | |
} else { | |
fprintf(stderr, "Failed to get title name (name field not present).\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
/* Parse title_id. */ | |
if (!cJSON_GetU64(npdm_json, "title_id", &kip_hdr->TitleId)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
/* Parse various config. */ | |
if (!cJSON_GetU8(npdm_json, "main_thread_priority", &kip_hdr->MainThreadPriority)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_GetU8(npdm_json, "default_cpu_id", &kip_hdr->DefaultCpuId)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_GetU8(npdm_json, "process_category", (u8 *)&kip_hdr->ProcessCategory)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
/* Parse capabilities. */ | |
capabilities = cJSON_GetObjectItemCaseSensitive(npdm_json, "kernel_capabilities"); | |
if (!cJSON_IsArray(capabilities)) { | |
fprintf(stderr, "Kernel Capabilities must be an array!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
u32 cur_cap = 0; | |
u32 desc; | |
cJSON_ArrayForEach(capability, capabilities) { | |
desc = 0; | |
if (!cJSON_IsObject(capability)) { | |
fprintf(stderr, "Kernel Capabilities must all be objects!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
const cJSON *type = cJSON_GetObjectItemCaseSensitive(capability, "type"); | |
char *type_str; | |
if (cJSON_IsString(type_str) && (type_str->valuestring != NULL)) { | |
type_str = type->valuestring; | |
} else { | |
fprintf(stderr, "Failed to get capability type (field not present).\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
const cJSON *value = cJSON_GetObjectItemCaseSensitive(capability, "value"); | |
if (strcmp(type_str, "kernel_flags")) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_IsObject(value)) { | |
fprintf(stderr, "Kernel Flags Capability value must be object!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
u8 highest_prio = 0, lowest_prio = 0, lowest_cpu = 0, highest_cpu = 0; | |
if (!cJSON_GetU8(value, "highest_thread_priority", &highest_prio) || | |
!cJSON_GetU8(value, "lowest_thread_priority", &lowest_prio) || | |
!cJSON_GetU8(value, "highest_cpu_id", &highest_cpu) || | |
!cJSON_GetU8(value, "lowest_cpu_id", &lowest_cpu)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
desc = highest_cpu_id; | |
desc <<= 8; | |
desc |= lowest_cpu; | |
desc <<= 8; | |
desc |= (lowest_thread_priority & 0x3F); | |
desc <<= 6; | |
desc |= (highest_thread_priority & 0x3F); | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 4) | (0x0007)); | |
} else if (strcmp(type_str, "syscalls")) { | |
if (!cJSON_IsObject(value)) { | |
fprintf(stderr, "Syscalls Capability value must be object!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
u32 num_descriptors; | |
u32 descriptors[6] = {0}; /* alignup(0x80/0x18); */ | |
char field_name[8] = {0}; | |
int cur; | |
for (unsigned int i = 0; i < 0x80; i++) { | |
snprintf(field_name, 8, "0x%02x", i); | |
if (!cJSON_GetBooleanOptional(value, field_name, &cur)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
descriptors[i / 0x18] |= (1UL << (i % 0x18)); | |
} | |
for (unsigned int i = 0; i < 6; i++) { | |
if (descriptors[i]) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
desc = descriptors[i] | (i << 24); | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 5) | (0x000F)); | |
} | |
} | |
} else if (strcmp(type_str, "map")) { | |
if (cur_cap + 2 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_IsObject(value)) { | |
fprintf(stderr, "Map Capability value must be object!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
u64 map_address = 0; | |
u64 map_size = 0; | |
int is_ro; | |
int is_io; | |
if (!cJSON_GetU64(value, "address", &map_address) || | |
!cJSON_GetU64(value, "size", &map_size) || | |
!cJSON_GetBoolean(value, "is_ro", &is_ro) || | |
!cJSON_GetBoolean(value, "is_io", &is_io)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
desc = (u32)((map_address >> 12) & 0x00FFFFFFULL); | |
desc |= is_ro << 24; | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 7) | (0x003F)); | |
desc = (u32)((map_size >> 12) & 0x00FFFFFFULL); | |
is_io ^= 1; | |
desc |= is_io << 24; | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 7) | (0x003F)); | |
} else if (strcmp(type_str, "map_page")) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
u64 page_address = 0; | |
if (!cJSON_GetU64(capability, "value", &page_address)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
desc = (u32)((page_address >> 12) & 0x00FFFFFFULL); | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 8) | (0x007F)); | |
} else if (strcmp(type_str, "irq_pair")) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_IsArray(value) || cJSON_GetArraySize(value) != 2) { | |
fprintf(stderr, "Error: IRQ Pairs must have size 2 array value.\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
const cJSON *irq = NULL; | |
cJSON_ArrayForEach(irq, value) { | |
desc <<= 10; | |
if (cJSON_IsNull(irq)) { | |
desc |= 0x3FF; | |
} else if (cJSON_IsNumber(config)) { | |
desc |= ((u16)(config->valueint)) & 0x3FF; | |
} else { | |
fprintf(stderr, "Failed to parse IRQ value.\n", field); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
} | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 12) | (0x07FF)); | |
} else if (strcmp(type_str, "application_type")) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_GetU16(capability, "value", (u8 *)&desc)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
desc &= 7; | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 14) | (0x1FFF)); | |
} else if (strcmp(type_str, "min_kernel_version")) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_GetU16(capability, "value", (u16 *)&desc)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 15) | (0x3FFF)); | |
} else if (strcmp(type_str, "handle_table_size")) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_GetU16(capability, "value", (u16 *)&desc)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 16) | (0x7FFF)); | |
} else if (strcmp(type_str, "debug_flags")) { | |
if (cur_cap + 1 > 0x20) { | |
fprintf(stderr, "Error: Too many capabilities!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_IsObject(value)) { | |
fprintf(stderr, "Debug Flag Capability value must be object!\n"); | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
int allow_debug = 0; | |
int force_debug = 0; | |
if (!cJSON_GetBoolean(value, "allow_debug", &allow_debug)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
if (!cJSON_GetBoolean(value, "force_debug", &force_debug)) { | |
status = 0; | |
goto PARSE_CAPS_END; | |
} | |
desc = (allow_debug & 1) | ((force_debug & 1) << 1); | |
kip_hdr->capabilities[cur_cap++] = (u32)((desc << 17) | (0xFFFF)); | |
} | |
} | |
PARSE_CAPS_END: | |
cJSON_Delete(npdm_json); | |
return status; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment