int encdec_init(void) { u64 muid, dma_bus_addr; int result; result = lv1_allocate_memory(ENCDEC_DMA_SIZE, ENCDEC_DMA_PAGE_SIZE, 0, 0, &encdec_buf_lpar_addr, &muid); if (result != 0) return result; result = lv1_allocate_device_dma_region(ENCDEC_BUS_ID, ENCDEC_DEV_ID, ENCDEC_DMA_SIZE, ENCDEC_DMA_PAGE_SIZE, 0, &dma_bus_addr); if (result != 0) return result; result = lv1_map_device_dma_region(ENCDEC_BUS_ID, ENCDEC_DEV_ID, encdec_buf_lpar_addr, dma_bus_addr, ENCDEC_DMA_SIZE, 0xF800000000000000ULL); if (result != 0) return result; MM_LOAD_BASE(encdec_buf, ENCDEC_DMA_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA((u64) encdec_buf), encdec_buf_lpar_addr, ENCDEC_DMA_SIZE, ENCDEC_DMA_PAGE_SIZE, 0, 0); if (result != 0) return result; memset(encdec_buf, 0, ENCDEC_DMA_SIZE); return 0; }
int query_lpar_address(void) { u64 lpar_addr, start_address, size, access_right, max_page_size, flags; u64 entries[3][7]; u64 *ptr; int i, result; MM_LOAD_BASE(ptr, QUERY_LPAR_ADDR_OFFSET); lpar_addr = 0x0000000000000000ULL; result = lv1_query_logical_partition_address_region_info(lpar_addr, &start_address, &size, &access_right, &max_page_size, &flags); i = 0; entries[i][0] = result; entries[i][1] = lpar_addr; entries[i][2] = start_address; entries[i][3] = size; entries[i][4] = access_right; entries[i][5] = max_page_size; entries[i][6] = flags; lpar_addr = *((u64 *) (*(u64 *) (*(u64 *) ptr)) + 0x11); result = lv1_query_logical_partition_address_region_info(lpar_addr, &start_address, &size, &access_right, &max_page_size, &flags); i++; entries[i][0] = result; entries[i][1] = lpar_addr; entries[i][2] = start_address; entries[i][3] = size; entries[i][4] = access_right; entries[i][5] = max_page_size; entries[i][6] = flags; lpar_addr = *((u64 *) (*(u64 *) (*(u64 *) ptr)) + 0x13); result = lv1_query_logical_partition_address_region_info(lpar_addr, &start_address, &size, &access_right, &max_page_size, &flags); i++; entries[i][0] = result; entries[i][1] = lpar_addr; entries[i][2] = start_address; entries[i][3] = size; entries[i][4] = access_right; entries[i][5] = max_page_size; entries[i][6] = flags; result = gelic_xmit_data(gelic_bcast_mac_addr, 0xCAFE, entries, sizeof(entries)); if (result < 0) return result; return 0; }
int vuart_dispmgr(void) { #define N(a) (sizeof((a)) / sizeof((a)[0])) static u64 subject_id[][2] = { { 0x1070000002000001, 0x10700003FF000001 }, { 0x1070000002000001, 0x10700005FC000001 }, { 0x1070000002000001, 0x10700003FD000001 }, { 0x1070000002000001, 0x1070000300000001 }, }; u64 vuart_lpar_addr, muid, lpar_addr, ea_addr, nread, nwritten, val; void *msgbuf; struct dispmgr_header *dispmgr_header; struct ss_header *ss_header; struct ss_update_mgr_get_package_info *ss_update_mgr_get_package_info; int i, result; result = lv1_allocate_memory(VUART_DISPMGR_SIZE, VUART_DISPMGR_PAGE_SIZE, 0, 0, &vuart_lpar_addr, &muid); if (result != 0) return result; MM_LOAD_BASE(ea_addr, VUART_DISPMGR_OFFSET); lpar_addr = vuart_lpar_addr; for (i = 0; i < VUART_DISPMGR_SIZE >> 12; i++) { result = mm_insert_htab_entry(MM_EA2VA(ea_addr), lpar_addr, 0); if (result != 0) return result; ea_addr += (1 << 12); lpar_addr += (1 << 12); } MM_LOAD_BASE(msgbuf, VUART_DISPMGR_OFFSET); for (i = 0; i < N(subject_id); i++) { memset(msgbuf, 0, VUART_DISPMGR_SIZE); dispmgr_header = (struct dispmgr_header *) msgbuf; dispmgr_header->version = 1; dispmgr_header->function_id = 0x6000; dispmgr_header->request_size = 0x28; dispmgr_header->response_size = 0x100; ss_header = (struct ss_header *) (dispmgr_header + 1); memset(ss_header, 0, sizeof(struct ss_header)); ss_header->packet_id = 0x6003; ss_header->function_id = 0x6000; ss_header->laid = subject_id[i][0]; ss_header->paid = subject_id[i][1]; ss_update_mgr_get_package_info = (struct ss_update_mgr_get_package_info *) (ss_header + 1); memset(ss_update_mgr_get_package_info, 0, sizeof(struct ss_update_mgr_get_package_info)); ss_update_mgr_get_package_info->type = 1; dispmgr_header->request_size += sizeof(struct ss_update_mgr_get_package_info); result = lv1_write_virtual_uart(DISPMGR_VUART_PORT, vuart_lpar_addr, sizeof(struct dispmgr_header) + sizeof(struct ss_header) + sizeof(struct ss_update_mgr_get_package_info), &nwritten); if (result < 0) return result; for (;;) { result = lv1_get_virtual_uart_param(DISPMGR_VUART_PORT, VUART_PARAM_RX_BYTES, &val); if (result < 0) return result; if (val != 0) break; } for (;;) { result = lv1_read_virtual_uart(DISPMGR_VUART_PORT, vuart_lpar_addr, VUART_DISPMGR_SIZE, &nread); if (result < 0) return result; if (nread == 0) break; result = gelic_xmit_data(gelic_bcast_mac_addr, 0xCAFE, msgbuf, nread); if (result < 0) return result; } } return 0; #undef N }
int aim_get_open_ps_id(void) { #define N(a) (sizeof((a)) / sizeof((a)[0])) u64 vuart_lpar_addr, muid, nread, nwritten; u8 *msgbuf; struct dispmgr_header *dispmgr_header; struct ss_header *ss_header; struct ss_aim_get_open_ps_id *ss_aim_get_open_ps_id; int result; result = lv1_allocate_memory(AIM_GET_OPEN_PS_ID_SIZE, AIM_GET_OPEN_PS_ID_PAGE_SIZE, 0, 0, &vuart_lpar_addr, &muid); if (result != 0) return result; MM_LOAD_BASE(msgbuf, AIM_GET_OPEN_PS_ID_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA((u64) msgbuf), vuart_lpar_addr, AIM_GET_OPEN_PS_ID_SIZE, AIM_GET_OPEN_PS_ID_PAGE_SIZE, 0, 0); if (result != 0) return result; memset(msgbuf, 0, AIM_GET_OPEN_PS_ID_SIZE); dispmgr_header = (struct dispmgr_header *) msgbuf; dispmgr_header->request_id = 1; dispmgr_header->function_id = 0x19000; dispmgr_header->request_size = sizeof(struct ss_header); dispmgr_header->response_size = sizeof(struct ss_header) + sizeof(struct ss_aim_get_open_ps_id); ss_header = (struct ss_header *) (dispmgr_header + 1); memset(ss_header, 0, sizeof(struct ss_header)); ss_header->packet_id = 0x19005; ss_header->function_id = 0x19000; ss_header->laid = subject_id[0]; ss_header->paid = subject_id[1]; ss_aim_get_open_ps_id = (struct ss_aim_get_open_ps_id *) (ss_header + 1); memset(ss_aim_get_open_ps_id, 0, sizeof(struct ss_aim_get_open_ps_id)); dispmgr_header->request_size += sizeof(struct ss_aim_get_open_ps_id); result = lv1_write_virtual_uart(DISPMGR_VUART_PORT, vuart_lpar_addr, sizeof(struct dispmgr_header) + dispmgr_header->request_size, &nwritten); if (result < 0) return result; result = vuart_wait_for_rx_data(DISPMGR_VUART_PORT); if (result < 0) return result; result = lv1_read_virtual_uart(DISPMGR_VUART_PORT, vuart_lpar_addr, AIM_GET_OPEN_PS_ID_SIZE, &nread); if (result < 0) return result; result = gelic_xmit_data(gelic_bcast_mac_addr, 0xBEEF, msgbuf, nread); if (result < 0) return result; beep(BEEP_DOUBLE); lv1_panic(1); return 0; #undef N }
int product_mode_off(void) { u64 vuart_lpar_addr, muid, nread, nwritten; u8 *msgbuf; struct dispmgr_header *dispmgr_header; struct ss_header *ss_header; struct ss_update_mgr_write_eprom *ss_update_mgr_write_eprom; int result; result = lv1_allocate_memory(PRODUCT_MODE_SIZE, PRODUCT_MODE_PAGE_SIZE, 0, 0, &vuart_lpar_addr, &muid); if (result != 0) return result; MM_LOAD_BASE(msgbuf, PRODUCT_MODE_OFFSET); result = mm_map_lpar_memory_region(0, (u64) msgbuf, vuart_lpar_addr, PRODUCT_MODE_SIZE, PRODUCT_MODE_PAGE_SIZE, 0, 0); if (result != 0) return result; memset(msgbuf, 0, PRODUCT_MODE_SIZE); dispmgr_header = (struct dispmgr_header *) msgbuf; dispmgr_header->request_id = 1; dispmgr_header->function_id = 0x6000; dispmgr_header->request_size = sizeof(struct ss_header); dispmgr_header->response_size = sizeof(struct ss_header) + sizeof(struct ss_update_mgr_write_eprom); ss_header = (struct ss_header *) (dispmgr_header + 1); memset(ss_header, 0, sizeof(struct ss_header)); ss_header->packet_id = 0x600C; ss_header->function_id = 0x6000; ss_header->laid = subject_id[0]; ss_header->paid = subject_id[1]; ss_update_mgr_write_eprom = (struct ss_update_mgr_write_eprom *) (ss_header + 1); memset(ss_update_mgr_write_eprom, 0, sizeof(struct ss_update_mgr_write_eprom)); ss_update_mgr_write_eprom->offset = 0x48C07; ss_update_mgr_write_eprom->value = 0xFF; dispmgr_header->request_size += sizeof(struct ss_update_mgr_write_eprom); result = lv1_write_virtual_uart(DISPMGR_VUART_PORT, vuart_lpar_addr, sizeof(struct dispmgr_header) + dispmgr_header->request_size, &nwritten); if (result < 0) return result; result = vuart_wait_for_rx_data(DISPMGR_VUART_PORT); if (result < 0) return result; result = lv1_read_virtual_uart(DISPMGR_VUART_PORT, vuart_lpar_addr, PRODUCT_MODE_SIZE, &nread); if (result < 0) return result; result = gelic_xmit_data(gelic_bcast_mac_addr, 0xBEEF, msgbuf, nread); if (result < 0) return result; beep(BEEP_DOUBLE); lv1_panic(1); return 0; }
int vuart_sysmgr(void) { u64 lpar_addr, muid, nread, nwritten, val; void *msgbuf; struct sysmgr_header *header; struct sysmgr_ctrl_led *ctrl_led; struct sysmgr_ring_buzzer *ring_buzzer; int result; result = lv1_allocate_memory(VUART_SYSMGR_SIZE, VUART_SYSMGR_PAGE_SIZE, 0, 0, &lpar_addr, &muid); if (result != 0) return result; result = mm_insert_htab_entry(MM_EA2VA(VUART_SYSMGR_BASE), lpar_addr, 0); if (result != 0) return result; MM_LOAD_BASE(msgbuf, VUART_SYSMGR_OFFSET); header = (struct sysmgr_header *) msgbuf; memset(header, 0, sizeof(struct sysmgr_header)); header->version = 1; header->size = 16; header->payload_size = 16; header->sid = SYSMGR_SID_CTRL_LED; ctrl_led = (struct sysmgr_ctrl_led *) (header + 1); memset(ctrl_led, 0, sizeof(struct sysmgr_ctrl_led)); ctrl_led->field0 = 1; ctrl_led->field1 = 0; ctrl_led->field2 = 0xFF; ctrl_led->field4 = 0xFF; ctrl_led->field5 = 0xFF; result = lv1_write_virtual_uart(SYSMGR_VUART_PORT, lpar_addr, sizeof(struct sysmgr_header) + sizeof(struct sysmgr_ctrl_led), &nwritten); if (result < 0) return result; header = (struct sysmgr_header *) msgbuf; memset(header, 0, sizeof(struct sysmgr_header)); header->version = 1; header->size = 16; header->payload_size = 8; header->sid = SYSMGR_SID_RING_BUZZER; ring_buzzer = (struct sysmgr_ring_buzzer *) (header + 1); memset(ring_buzzer, 0, sizeof(struct sysmgr_ring_buzzer)); ring_buzzer->field1 = 0x29; ring_buzzer->field2 = 0x4; ring_buzzer->field4 = 0x6; result = lv1_write_virtual_uart(SYSMGR_VUART_PORT, lpar_addr, sizeof(struct sysmgr_header) + sizeof(struct sysmgr_ring_buzzer), &nwritten); if (result < 0) return result; for (;;) { result = lv1_get_virtual_uart_param(SYSMGR_VUART_PORT, VUART_PARAM_RX_BYTES, &val); if (result < 0) return result; if (val == 0) continue; result = lv1_read_virtual_uart(SYSMGR_VUART_PORT, lpar_addr, VUART_SYSMGR_SIZE, &nread); if (result < 0) return result; result = gelic_xmit_data(gelic_bcast_mac_addr, 0xCAFE, msgbuf, nread); if (result < 0) return result; } return 0; }
int payload_main(uint8_t* output_data, uint64_t output_size) { int result; uint64_t ticks; uint64_t hv_lpar_addr; uint64_t hv_mapped_size; uint8_t* hv; uint8_t* metldr; uint8_t* stuff; uint8_t* dumper; uint8_t* work_data; uint64_t metldr_offset, metldr_size; uint64_t stuff_lpar_addr; uint64_t gameos_lpar_base, gameos_lpar_size; uint64_t vas_id, spu_id; uint64_t esid, vsid; uint64_t priv2_addr, problem_phys, local_store_phys, shadow_addr; uint64_t intr_status, unused; struct spu_shadow volatile* spu_shadow; struct spu_problem volatile* spu_problem; struct spu_priv2 volatile* spu_priv2; uint8_t volatile* spu_ls; uint32_t spu_out_intr_mbox_value, spu_out_mbox_value; uint8_t mfc_cmd_tag; uint32_t force_exit; uint32_t i; lv2_extend_kstack(0); result = 0; hv = NULL; metldr = NULL; stuff = NULL; dumper = NULL; work_data = NULL; hv_lpar_addr = 0; stuff_lpar_addr = 0; if (!output_data || output_size < DUMP_SIZE) { result = EINVAL; goto error; } gameos_lpar_base = *(uint64_t*)GAMEOS_LPAR_BASE_PTR; gameos_lpar_size = *(uint64_t*)GAMEOS_LPAR_SIZE_PTR; if (!gameos_lpar_base || !gameos_lpar_size) { result = EFAULT; goto error; } metldr_offset = lv1_peek64(LOADERS_TAB_OFFSET + METLDR_TAB_OFFSET); metldr_size = lv1_peek64(LOADERS_TAB_OFFSET + METLDR_TAB_SIZE); if (!metldr_offset || !metldr_size) { result = EFAULT; goto error; } hv_mapped_size = align_up(metldr_offset + metldr_size, 1 << HV_PAGE_SIZE); result = lv1_undocumented_function_114(0, HV_PAGE_SIZE, hv_mapped_size, &hv_lpar_addr); if (result != 0) goto error; MM_LOAD_BASE(hv, HV_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA(hv), hv_lpar_addr, hv_mapped_size, HV_PAGE_SIZE, 0, 0); if (result != 0) goto error; stuff_lpar_addr = gameos_lpar_base + gameos_lpar_size - STUFF_SIZE; MM_LOAD_BASE(stuff, STUFF_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA(stuff), stuff_lpar_addr, STUFF_SIZE, STUFF_PAGE_SIZE, 0, 0); if (result != 0) goto error; metldr = stuff; dumper = ptr_align_up(metldr + metldr_size, 1 << STUFF_PAGE_SIZE); work_data = ptr_align_up(dumper + dumper_payload_size, 1 << STUFF_PAGE_SIZE); lv2_memcpy(metldr, hv + metldr_offset, metldr_size); lv2_memcpy(dumper, dumper_payload, dumper_payload_size); lv2_memset(work_data, 0, DUMP_SIZE); result = lv1_undocumented_function_115(hv_lpar_addr); if (result != 0) goto done; hv_lpar_addr = 0; vas_id = vas_get_id(); result = lv1_construct_logical_spu(PAGE_SIZE_4KB, PAGE_SIZE_4KB, PAGE_SIZE_4KB, PAGE_SIZE_4KB, PAGE_SIZE_4KB, vas_id, 0, &priv2_addr, &problem_phys, &local_store_phys, &unused, &shadow_addr, &spu_id); if (result != 0) goto error; result = lv1_enable_logical_spu(spu_id, 6); if (result != 0) goto error; result = lv1_set_spu_interrupt_mask(spu_id, 0, 0x7); if (result != 0) goto error; result = lv1_set_spu_interrupt_mask(spu_id, 1, 0xF); if (result != 0) goto error; result = lv1_set_spu_interrupt_mask(spu_id, 2, 0xF); if (result != 0) goto error; MM_LOAD_BASE(spu_shadow, SPU_SHADOW_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA(spu_shadow), shadow_addr, SPU_SHADOW_SIZE, PAGE_SIZE_4KB, 0, 0x3); if (result != 0) goto error; MM_LOAD_BASE(spu_problem, SPU_PROBLEM_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA(spu_problem), problem_phys, SPU_PROBLEM_SIZE, PAGE_SIZE_4KB, 0, 0); if (result != 0) goto error; MM_LOAD_BASE(spu_priv2, SPU_PRIV2_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA(spu_priv2), priv2_addr, SPU_PRIV2_SIZE, PAGE_SIZE_4KB, 0, 0); if (result != 0) goto error; MM_LOAD_BASE(spu_ls, SPU_LS_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA(spu_ls), local_store_phys, SPU_LS_SIZE, PAGE_SIZE_4KB, 0, 0); if (result != 0) goto error; result = lv1_set_spu_privilege_state_area_1_register(spu_id, MFC_SR1, 0x10); if (result != 0) goto error; spu_slb_invalidate_all(spu_priv2); esid = 0x8000000018000000ULL; vsid = 0x0000000000001400ULL; spu_slb_set_entry(spu_priv2, 0, esid, vsid); spu_priv2->spu_cfg = 0; eieio(); spu_in_mbox_write_64(spu_problem, (uint64_t)dumper); spu_sig_notify_1_2_write_64(spu_problem, (uint64_t)metldr); spu_iso_load_req_enable(spu_priv2); spu_iso_load_req(spu_problem); force_exit = 0; while (1) { if (force_exit) { result = ECANCELED; goto bad; } result = lv1_get_spu_interrupt_status(spu_id, 0, &intr_status); if (result != 0) goto error; if (intr_status) { result = lv1_clear_spu_interrupt_status(spu_id, 0, intr_status, 0); if (result != 0) goto error; } result = lv1_get_spu_interrupt_status(spu_id, 1, &intr_status); if (result != 0) goto error; if (intr_status) { result = lv1_clear_spu_interrupt_status(spu_id, 1, intr_status, 0); if (result != 0) goto error; } result = lv1_get_spu_interrupt_status(spu_id, 2, &intr_status); if (result != 0) goto error; if (intr_status) { result = lv1_clear_spu_interrupt_status(spu_id, 2, intr_status, 0); if (result != 0) goto error; if (intr_status & 0x1) { if (spu_mbox_stat_intr_out_mbox_count(spu_problem) != 0) { spu_out_intr_mbox_value = spu_priv2->spu_out_intr_mbox; if (spu_out_intr_mbox_value == 1) { if (spu_mbox_stat_out_mbox_count(spu_problem) == 0) { result = ECANCELED; goto bad; } spu_out_mbox_value = spu_problem->spu_out_mbox; if (spu_out_mbox_value != 1) { result = ECANCELED; break; } ticks = 3 * TB_TICKS_PER_SEC; sleep(ticks); mfc_cmd_tag = 1; if (spu_mfc_cmd_exec(spu_problem, DUMP_LS_ADDR, (uint64_t)work_data, DUMP_SIZE, mfc_cmd_tag, 0, MFC_CMD_PUT)) { result = ECANCELED; goto bad; } while (spu_mfc_cmd_tag_status(spu_problem, mfc_cmd_tag) == 0) { if (force_exit) { result = ECANCELED; goto bad; } } force_exit = 1; } else if (spu_out_intr_mbox_value == 2) { spu_out_mbox_value = spu_problem->spu_out_mbox; force_exit = 1; } } } } if ((spu_problem->spu_status & 0x1) == 0) break; ticks = 1 * TB_TICKS_PER_SEC; sleep(ticks); } bad: if (spu_shadow) { } if (spu_problem) { spu_iso_exit_req(spu_problem); spu_stop_req(spu_problem); } if (spu_priv2) { } result = lv1_destruct_logical_spu(spu_id); if (result != 0) goto error; if (work_data) result = lv2_copy_to_user(work_data, output_data, DUMP_SIZE); ticks = 5 * TB_TICKS_PER_SEC; sleep(ticks); error: if (hv_lpar_addr != 0) result = lv1_undocumented_function_115(hv_lpar_addr); done: return result; }