Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 48 additions & 10 deletions src/elf2kip.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ uint8_t* ReadEntireFile(const char* fn, size_t* len_out) {
return buf;
}

int cJSON_GetString(const cJSON *obj, const char *field, const char **out) {
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field);
if (cJSON_IsString(config)) {
*out = config->valuestring;
return 1;
} else {
fprintf(stderr, "Failed to get %s (field not present).\n", field);
return 0;
}
}

int cJSON_GetU8(const cJSON *obj, const char *field, u8 *out) {
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field);
if (cJSON_IsNumber(config)) {
Expand Down Expand Up @@ -237,19 +248,37 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {

/* Parse capabilities. */
capabilities = cJSON_GetObjectItemCaseSensitive(npdm_json, "kernel_capabilities");
if (!cJSON_IsObject(capabilities)) {
fprintf(stderr, "Kernel Capabilities must be an object!\n");
if (!(cJSON_IsArray(capabilities) || cJSON_IsObject(capabilities))) {
fprintf(stderr, "Kernel Capabilities must be an array!\n");
status = 0;
goto PARSE_CAPS_END;
}


int kac_obj = 0;
if (cJSON_IsObject(capabilities)) {
kac_obj = 1;
fprintf(stderr, "Using deprecated kernel_capabilities format. Please turn it into an array.\n");
}

u32 cur_cap = 0;
u32 desc;
cJSON_ArrayForEach(capability, capabilities) {
desc = 0;
const char *type_str = capability->string;

const cJSON *value = capability;
const char *type_str;
const cJSON *value;

if (kac_obj) {
type_str = capability->string;
value = capability;
} else {
if (!cJSON_GetString(capability, "type", &type_str)) {
status = 0;
goto PARSE_CAPS_END;
}
value = cJSON_GetObjectItemCaseSensitive(capability, "value");
}


if (!strcmp(type_str, "kernel_flags")) {
if (cur_cap + 1 > 0x20) {
fprintf(stderr, "Error: Too many capabilities!\n");
Expand Down Expand Up @@ -370,17 +399,18 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
goto PARSE_CAPS_END;
}
const cJSON *irq = NULL;
int desc_idx = 0;
cJSON_ArrayForEach(irq, value) {
desc <<= 10;
if (cJSON_IsNull(irq)) {
desc |= 0x3FF;
desc |= 0x3FF << desc_idx;
} else if (cJSON_IsNumber(irq)) {
desc |= ((u16)(irq->valueint)) & 0x3FF;
desc |= (((u16)(irq->valueint)) & 0x3FF) << desc_idx;
} else {
fprintf(stderr, "Failed to parse IRQ value.\n");
status = 0;
goto PARSE_CAPS_END;
}
desc_idx += 10;
}
kip_hdr->Capabilities[cur_cap++] = (u32)((desc << 12) | (0x07FF));
} else if (!strcmp(type_str, "application_type")) {
Expand Down Expand Up @@ -445,13 +475,18 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
}
desc = (allow_debug & 1) | ((force_debug & 1) << 1);
kip_hdr->Capabilities[cur_cap++] = (u32)((desc << 17) | (0xFFFF));
} else {
fprintf(stderr, "Error: unknown capability %s\n", type_str);
status = 0;
goto PARSE_CAPS_END;
}
}

for (u32 i = cur_cap; i < 0x20; i++) {
kip_hdr->Capabilities[i] = 0xFFFFFFFF;
}

status = 1;
PARSE_CAPS_END:
cJSON_Delete(npdm_json);
return status;
Expand Down Expand Up @@ -479,7 +514,10 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE;
}

ParseKipConfiguration(json, &kip_hdr);
if (!ParseKipConfiguration(json, &kip_hdr)) {
fprintf(stderr, "Failed to parse kip configuration!\n");
return EXIT_FAILURE;
}

size_t elf_len;
uint8_t* elf = ReadEntireFile(argv[1], &elf_len);
Expand Down
129 changes: 108 additions & 21 deletions src/npdmtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@ uint8_t* ReadEntireFile(const char* fn, size_t* len_out) {
return buf;
}

int cJSON_GetString(const cJSON *obj, const char *field, const char **out) {
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field);
if (cJSON_IsString(config)) {
*out = config->valuestring;
return 1;
} else {
fprintf(stderr, "Failed to get %s (field not present).\n", field);
return 0;
}
}

int cJSON_GetU8(const cJSON *obj, const char *field, u8 *out) {
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field);
if (cJSON_IsNumber(config)) {
Expand Down Expand Up @@ -372,35 +383,93 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
aci0->SacOffset = (aci0->FahOffset + aci0->FahSize + 0xF) & ~0xF;

/* Sac. */
services = cJSON_GetObjectItemCaseSensitive(npdm_json, "service_access");
if (!cJSON_IsObject(services)) {
fprintf(stderr, "Service Access must be an object!\n");
u8 *sac = (u8*)aci0 + aci0->SacOffset;
u32 sac_size = 0;

services = cJSON_GetObjectItemCaseSensitive(npdm_json, "service_host");
if (!cJSON_IsArray(services)) {
fprintf(stderr, "Service Host must be an array!\n");
status = 0;
goto NPDM_BUILD_END;
}

u8 *sac = (u8*)aci0 + aci0->SacOffset;
u32 sac_size = 0;

cJSON_ArrayForEach(service, services) {
if (!cJSON_IsBool(service)) {
fprintf(stderr, "Services must be of form service_name (str) : is_host (bool)\n");
int is_host = 1;
char *service_name;

if (!cJSON_IsString(service)) {
fprintf(stderr, "service_access must be an array of string\n");
status = 0;
goto NPDM_BUILD_END;
}
int cur_srv_len = strlen(service->string);
service_name = service->valuestring;

int cur_srv_len = strlen(service_name);
if (cur_srv_len > 8 || cur_srv_len == 0) {
fprintf(stderr, "Services must have name length 1 <= len <= 8!\n");
status = 0;
goto NPDM_BUILD_END;
}
u8 ctrl = (u8)(cur_srv_len - 1);
if (is_host) {
ctrl |= 0x80;
}
sac[sac_size++] = ctrl;
memcpy(sac + sac_size, service_name, cur_srv_len);
sac_size += cur_srv_len;
}

services = cJSON_GetObjectItemCaseSensitive(npdm_json, "service_access");
if (!(cJSON_IsObject(services) || cJSON_IsArray(services))) {
fprintf(stderr, "Service Access must be an array!\n");
status = 0;
goto NPDM_BUILD_END;
}

int sac_obj = 0;
if (cJSON_IsObject(services)) {
sac_obj = 1;
fprintf(stderr, "Using deprecated service_access format. Please turn it into an array.\n");
}

cJSON_ArrayForEach(service, services) {
int is_host = 0;
char *service_name;

if (sac_obj) {
if (!cJSON_IsBool(service)) {
fprintf(stderr, "Services must be of form service_name (str) : is_host (bool)\n");
status = 0;
goto NPDM_BUILD_END;
}
is_host = cJSON_IsTrue(service);
service_name = service->string;
} else {
if (!cJSON_IsString(service)) {
fprintf(stderr, "service_access must be an array of string\n");
status = 0;
goto NPDM_BUILD_END;
}
is_host = 0;
service_name = service->valuestring;
}

int cur_srv_len = strlen(service_name);
if (cur_srv_len > 8 || cur_srv_len == 0) {
fprintf(stderr, "Services must have name length 1 <= len <= 8!\n");
status = 0;
goto NPDM_BUILD_END;
}
u8 ctrl = (u8)(cur_srv_len - 1);
if (cJSON_IsTrue(service)) {
if (is_host) {
ctrl |= 0x80;
}
sac[sac_size++] = ctrl;
memcpy(sac + sac_size, service->string, cur_srv_len);
memcpy(sac + sac_size, service_name, cur_srv_len);
sac_size += cur_srv_len;
}


memcpy((u8 *)acid + acid->SacOffset, sac, sac_size);
aci0->SacSize = sac_size;
acid->SacSize = sac_size;
Expand All @@ -409,20 +478,37 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {

/* Parse capabilities. */
capabilities = cJSON_GetObjectItemCaseSensitive(npdm_json, "kernel_capabilities");
if (!cJSON_IsObject(capabilities)) {
fprintf(stderr, "Kernel Capabilities must be an object!\n");
if (!(cJSON_IsArray(capabilities) || cJSON_IsObject(capabilities))) {
fprintf(stderr, "Kernel Capabilities must be an array!\n");
status = 0;
goto NPDM_BUILD_END;
}


int kac_obj = 0;
if (cJSON_IsObject(capabilities)) {
kac_obj = 1;
fprintf(stderr, "Using deprecated kernel_capabilities format. Please turn it into an array.\n");
}

u32 *caps = (u32 *)((u8 *)aci0 + aci0->KacOffset);
u32 cur_cap = 0;
u32 desc;
cJSON_ArrayForEach(capability, capabilities) {
desc = 0;
const char *type_str = capability->string;

const cJSON *value = capability;
const char *type_str;
const cJSON *value;

if (kac_obj) {
type_str = capability->string;
value = capability;
} else {
if (!cJSON_GetString(capability, "type", &type_str)) {
status = 0;
goto NPDM_BUILD_END;
}
value = cJSON_GetObjectItemCaseSensitive(capability, "value");
}

if (!strcmp(type_str, "kernel_flags")) {
if (!cJSON_IsObject(value)) {
fprintf(stderr, "Kernel Flags Capability value must be object!\n");
Expand Down Expand Up @@ -518,17 +604,18 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
goto NPDM_BUILD_END;
}
const cJSON *irq = NULL;
int desc_idx = 0;
cJSON_ArrayForEach(irq, value) {
desc <<= 10;
if (cJSON_IsNull(irq)) {
desc |= 0x3FF;
desc |= 0x3FF << desc_idx;
} else if (cJSON_IsNumber(irq)) {
desc |= ((u16)(irq->valueint)) & 0x3FF;
desc |= (((u16)(irq->valueint)) & 0x3FF) << desc_idx;
} else {
fprintf(stderr, "Failed to parse IRQ value.\n");
status = 0;
goto NPDM_BUILD_END;
}
desc_idx += 10;
}
caps[cur_cap++] = (u32)((desc << 12) | (0x07FF));
} else if (!strcmp(type_str, "application_type")) {
Expand All @@ -541,7 +628,7 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
} else if (!strcmp(type_str, "min_kernel_version")) {
u64 kern_ver = 0;
if (cJSON_IsNumber(value)) {
kern_ver = (u64)value->valueint;
kern_ver = (u64)value->valueint;
} else if (!cJSON_IsString(value) || !cJSON_GetU64FromObjectValue(value, &kern_ver)) {
fprintf(stderr, "Error: Kernel version must be integer or hex strings.\n");
status = 0;
Expand Down