#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "types.h"
#include "netrpc.h"
#include "lv1.h"
#include "spu.h"
#include "mm.h"
#include "util.h"
#define PS3HOST "192.168.1.2"
u8 *_read_file(const char *name, u32 *size)
{
u8 *buf;
u32 len;
FILE *fp;
if((fp = fopen(name, "rb")) == NULL)
{
printf("could not open %s\n", name);
return NULL;
}
//Read into buffer.
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
buf = (u8 *)malloc(sizeof(u8) * len);
fread(buf, sizeof(u8), len, fp);
fclose(fp);
//Set buffer size.
if(size != NULL)
*size = len;
return buf;
}
u64 _vas_get_id(netrpc_ctxt_t *ctxt)
{
u64 id;
netrpc_hvcall(ctxt, _N_lv1_get_logical_ppe_id, NULL, 0, &id, 1);
netrpc_hvcall(ctxt, _N_lv1_get_virtual_address_space_id_of_ppe, &id, 1, &id, 1);
return id;
}
s64 _get_spe_intr_status(netrpc_ctxt_t *ctxt, u64 spe_id, u64 cls, u64 *stat)
{
u64 args[] = {spe_id, cls};
return netrpc_hvcall(ctxt, _N_lv1_get_spe_interrupt_status, args, 2, stat, 1);
}
s64 _clr_spe_intr_status(netrpc_ctxt_t *ctxt, u64 spe_id, u64 cls, u64 stat)
{
u64 args[] = {spe_id, cls, stat, 0};
return netrpc_hvcall(ctxt, _N_lv1_clear_spe_interrupt_status, args, 4, NULL, 0);
}
#define LDR_BASE 0x100000
#define LDR_SIZE 0x2300000
#define METLDR_SIZE 0x100000
#define ISOLDR_SIZE 0x100000
#define SPU_SHADOW_SIZE 0x1000
#define SPU_PROBLEM_SIZE 0x20000
#define SPU_PRIV2_SIZE 0x20000
#define SPU_LS_SIZE 0x40000
//static volatile u64 ldr_lpar_addr = 0x700020000000ULL + 0xE900000ULL - LDR_SIZE;
static u64 esid = 0x8000000018000000;
static u64 vsid = 0x0000000000001400;
int main(int argc, char **argv)
{
netrpc_ctxt_t ctxt;
s64 res;
//Ohai.
printf("connecting...");
if(netrpc_connect(&ctxt, inet_addr(PS3HOST), NETRPC_PORT) < 0)
{
printf("error\n");
return 1;
}
printf("ok\n");
printf("ping...");
if(netrpc_ping(&ctxt) < 0)
{
printf("error\n");
return 1;
}
printf("ok\n");
//Get vas id.
u64 vas_id = _vas_get_id(&ctxt);
//File adresses.
u64 metldr_addr, isoldr_addr;
metldr_addr = LDR_BASE;
isoldr_addr = metldr_addr + METLDR_SIZE;
//Map region.
//res = mm_map_lpar_memory_region(&ctxt, vas_id, MM_EA2VA(metldr_addr), LDR_BASE /*ldr_lpar_addr*/, LDR_SIZE, 0xC, 0, 0);
//printf("map_lpar_memory_region : %lld\n", res);
netrpc_addmmio(&ctxt, LDR_BASE, LDR_SIZE);
printf("copy files out...");
//Read files.
u32 metldr_size;
u8 *metldr = _read_file("./data/metldr", &metldr_size);
u32 isoldr_size;
u8 *isoldr = _read_file("./data/isoldr", &isoldr_size);
//u8 *isoldr = _read_file("./data/isoldr_patched", &isoldr_size);
//Copy files out.
netrpc_memcpy_out(&ctxt, metldr_addr, metldr, metldr_size);
netrpc_memcpy_out(&ctxt, isoldr_addr, isoldr, isoldr_size);
//Cleanup.
free(metldr);
free(isoldr);
printf("done\n");
printf("construct spe...");
//Construct SPE.
u64 cspe_args[] = {0xc, 0xc, 0xc, 0xc, 0xc, vas_id, 0};
u64 cspe_res[] = {0, 0, 0, 0, 0, 0};
netrpc_hvcall(&ctxt, _N_lv1_construct_logical_spe, cspe_args, 7, cspe_res, 6);
//SPE info.
u64 priv2_addr, problem_addr, ls_addr, shadow_addr, spe_id;
priv2_addr = cspe_res[0];
problem_addr = cspe_res[1];
ls_addr = cspe_res[2];
shadow_addr = cspe_res[4];
spe_id = cspe_res[5];
netrpc_addmmio(&ctxt, priv2_addr, SPU_PRIV2_SIZE);
netrpc_addmmio(&ctxt, problem_addr, SPU_PROBLEM_SIZE);
netrpc_addmmio(&ctxt, shadow_addr, SPU_SHADOW_SIZE);
netrpc_addmmio(&ctxt, ls_addr, SPU_LS_SIZE);
printf("done\n priv2 @ 0x%016llx\n problem @ 0x%016llx\n ls @ 0x%016llx\n shadow @ 0x%016llx\n id : 0x%016llx\n",
priv2_addr, problem_addr, ls_addr, shadow_addr, spe_id);
printf("setup spe...");
//Setup SPE.
u64 setup_spe_args[] = {spe_id, 0, 0};
setup_spe_args[1] = 6;
netrpc_hvcall(&ctxt, _N_lv1_enable_logical_spe, setup_spe_args, 2, NULL, 0);
setup_spe_args[1] = 0;
setup_spe_args[2] = 0x7;
netrpc_hvcall(&ctxt, _N_lv1_set_spe_interrupt_mask, setup_spe_args, 3, NULL, 0);
setup_spe_args[1] = 1;
setup_spe_args[2] = 0xf;
netrpc_hvcall(&ctxt, _N_lv1_set_spe_interrupt_mask, setup_spe_args, 3, NULL, 0);
setup_spe_args[1] = 2;
setup_spe_args[2] = 0xf;
netrpc_hvcall(&ctxt, _N_lv1_set_spe_interrupt_mask, setup_spe_args, 3, NULL, 0);
printf("done\n");
u64 set_reg_args[] = {spe_id, _OFFSET_MFC_SR1, 0x10};
res = netrpc_hvcall(&ctxt, _N_lv1_set_spe_privilege_state_area_1_register, set_reg_args, 3, NULL, 0);
printf("set_spe_privilege_state_area_1_register : %lld\n", res);
printf("start spe in isolation mode...");
spu_slb_invalidate_all(&ctxt, priv2_addr);
spu_slb_set_entry(&ctxt, priv2_addr, 0, esid, vsid);
write_u64(&ctxt, SPU_RADDR(priv2_addr, _OFFSET_SPU_Cfg), 0);
netrpc_eieio(&ctxt);
spu_in_mbox_write_64(&ctxt, problem_addr, isoldr_addr);
spu_sig_notify_1_2_write_64(&ctxt, problem_addr, metldr_addr);
spu_isolation_req_enable(&ctxt, priv2_addr);
spu_isolation_req(&ctxt, problem_addr);
printf("done\n");
FILE *fp = fopen("ls.bin", "wb");
u32 spu_status, size = 0;
u64 intr_status;
while(1)
{
res = _get_spe_intr_status(&ctxt, spe_id, 0, &intr_status);
if(intr_status)
{
printf("intr_status (0) : %016llx\n", intr_status);
printf("clear_intr_status : %lld\n", _clr_spe_intr_status(&ctxt, spe_id, 0, intr_status));
}
res = _get_spe_intr_status(&ctxt, spe_id, 1, &intr_status);
if(intr_status)
{
printf("intr_status (1) : %016llx\n", intr_status);
printf("clear_intr_status : %lld\n", _clr_spe_intr_status(&ctxt, spe_id, 1, intr_status));
}
res = _get_spe_intr_status(&ctxt, spe_id, 2, &intr_status);
if(intr_status & 0x1)
{
printf("mailbox interrupt\n");
printf("intr_status (2) : %016llx\n", intr_status);
printf("clear_intr_status : %lld\n", _clr_spe_intr_status(&ctxt, spe_id, 2, intr_status));
}
/*
while(size <= 0x40000)
{
netrpc_eieio(&ctxt);
//Wait for mbox value to be written.
while(spu_mbox_stat_out_mbox_count(&ctxt, problem_addr) == 0);
//Read mbox value.
u32 mbox_value;
read_u32(&ctxt, SPU_RADDR(problem_addr, _OFFSET_SPU_Out_Mbox), &mbox_value);
netrpc_eieio(&ctxt);
//Write to file.
fwrite(&mbox_value, sizeof(u32), 1, fp);
size += 4;
printf("\rdumped 0x%08x of 0x40000", size);
usleep(10);
}
*/
read_u32(&ctxt, SPU_RADDR(problem_addr, _OFFSET_SPU_Status), &spu_status);
if((spu_status & 0x1) == 0)
break;
usleep(1000);
}
fclose(fp);
printf("\ndone\n");
printf("spu_status: 0x%08x\n", spu_status);
//Bye.
netrpc_close(&ctxt);
return 0;
}