sys_spu_image loading rewritten

This commit is contained in:
Nekotekina 2017-04-13 18:35:49 +03:00
parent db1b012a26
commit 402df68235
6 changed files with 109 additions and 81 deletions

View File

@ -26,7 +26,7 @@ s32 cellOvisInitializeOverlayTable(vm::ptr<void> ea_ovly_table, vm::cptr<char> e
return CELL_OK;
}
void cellOvisFixSpuSegments(vm::ptr<sys_spu_image_t> image)
void cellOvisFixSpuSegments(vm::ptr<sys_spu_image> image)
{
cellOvis.todo("cellOvisFixSpuSegments(image=*0x%x)", image);
}

View File

@ -17,7 +17,7 @@
logs::channel cellSpurs("cellSpurs", logs::level::notice);
s32 sys_spu_image_close(vm::ptr<sys_spu_image_t> img);
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img);
// TODO
struct cell_error_t
@ -1051,9 +1051,9 @@ s32 _spurs::initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 revision,
// Import SPURS kernel
spurs->spuImg.type = SYS_SPU_IMAGE_TYPE_USER;
spurs->spuImg.segs = vm::cast(vm::alloc(0x40000, vm::main));
spurs->spuImg.segs = vm::null;
spurs->spuImg.entry_point = isSecond ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR;
spurs->spuImg.nsegs = 1;
spurs->spuImg.nsegs = 0;
// Create a thread group for this SPURS context
std::memcpy(spuTgName.get_ptr(), spurs->prefix, spurs->prefixSize);

View File

@ -539,7 +539,7 @@ struct alignas(128) CellSpurs
atomic_t<u8> handlerExiting; // 0xD66
atomic_be_t<u32> enableEH; // 0xD68
be_t<u32> exception; // 0xD6C
sys_spu_image_t spuImg; // 0xD70
sys_spu_image spuImg; // 0xD70
be_t<u32> flags; // 0xD80
be_t<s32> spuPriority; // 0xD84
be_t<u32> ppuPriority; // 0xD88

View File

@ -28,21 +28,17 @@ s32 sys_spu_elf_get_segments(u32 elf_img, vm::ptr<sys_spu_segment> segments, s32
return CELL_OK;
}
s32 sys_spu_image_import(vm::ptr<sys_spu_image_t> img, u32 src, u32 type)
s32 sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
{
sysPrxForUser.warning("sys_spu_image_import(img=*0x%x, src=0x%x, type=%d)", img, src, type);
u32 entry, offset = LoadSpuImage(fs::file(vm::base(src), 0 - src), entry);
img->type = SYS_SPU_IMAGE_TYPE_USER;
img->entry_point = entry;
img->segs.set(offset); // TODO: writing actual segment info
img->nsegs = 1; // wrong value
// Load from memory (TODO)
img->load(fs::file{vm::base(src), 0 - src});
return CELL_OK;
}
s32 sys_spu_image_close(vm::ptr<sys_spu_image_t> img)
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img)
{
sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img);
@ -59,7 +55,7 @@ s32 sys_spu_image_close(vm::ptr<sys_spu_image_t> img)
return CELL_EINVAL;
}
verify(HERE), vm::dealloc(img->segs.addr(), vm::main); // Current rough implementation
img->free();
return CELL_OK;
}
@ -75,33 +71,26 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
return CELL_ENOENT;
}
u32 _entry;
LoadSpuImage(elf_file, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
sys_spu_image img;
img.load(elf_file);
img.deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
img.free();
*entry = _entry | 1;
*entry = img.entry_point | 1;
return CELL_OK;
}
s32 sys_raw_spu_image_load(ppu_thread& ppu, s32 id, vm::ptr<sys_spu_image_t> img)
s32 sys_raw_spu_image_load(ppu_thread& ppu, s32 id, vm::ptr<sys_spu_image> img)
{
sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img);
// TODO: use segment info
const auto stamp0 = get_system_time();
std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), img->segs.get_ptr(), 256 * 1024);
const auto stamp1 = get_system_time();
// Load SPU segments
img->deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
// Use MMIO
vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, img->entry_point | 1);
const auto stamp2 = get_system_time();
sysPrxForUser.error("memcpy() latency: %lldus", (stamp1 - stamp0));
sysPrxForUser.error("MMIO latency: %lldus", (stamp2 - stamp1));
return CELL_OK;
}

View File

@ -18,7 +18,7 @@ namespace vm { using namespace ps3; }
logs::channel sys_spu("sys_spu", logs::level::notice);
void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
void sys_spu_image::load(const fs::file& stream)
{
const spu_exec_object obj{stream};
@ -27,6 +27,13 @@ void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
fmt::throw_exception("Failed to load SPU image: %s" HERE, obj.get_error());
}
this->type = SYS_SPU_IMAGE_TYPE_KERNEL;
this->entry_point = obj.header.e_entry;
this->segs.set(vm::alloc(65 * 4096, vm::main));
this->nsegs = 0;
const u32 addr = this->segs.addr() + 4096;
sha1_context ctx;
u8 output[20];
@ -36,6 +43,8 @@ void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
for (const auto& shdr : obj.shdrs)
{
sha1_update(&ctx, reinterpret_cast<const u8*>(&shdr), sizeof(spu_exec_object::shdr_t));
LOG_NOTICE(SPU, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", shdr.sh_type, shdr.sh_addr, shdr.sh_size, shdr.sh_flags);
}
for (const auto& prog : obj.progs)
@ -43,14 +52,40 @@ void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
sha1_update(&ctx, reinterpret_cast<const u8*>(&prog), sizeof(spu_exec_object::phdr_t));
sha1_update(&ctx, reinterpret_cast<const u8*>(prog.bin.data()), prog.bin.size());
if (prog.p_type == 0x1 /* LOAD */)
LOG_NOTICE(SPU, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY)
{
std::memcpy(vm::base(addr + prog.p_vaddr), prog.bin.data(), prog.p_filesz);
auto& seg = segs[nsegs++];
seg.type = prog.p_type;
seg.ls = prog.p_vaddr;
seg.addr = addr + prog.p_vaddr;
seg.size = std::min(prog.p_filesz, prog.p_memsz);
std::memcpy(vm::base(seg.addr), prog.bin.data(), seg.size);
if (prog.p_memsz > prog.p_filesz)
{
auto& zero = segs[nsegs++];
zero.type = SYS_SPU_SEGMENT_TYPE_FILL;
zero.ls = prog.p_vaddr + prog.p_filesz;
zero.addr = 0;
zero.size = prog.p_memsz - seg.size;
}
}
else if (prog.p_type == SYS_SPU_SEGMENT_TYPE_INFO)
{
auto& seg = segs[nsegs++];
seg.type = SYS_SPU_SEGMENT_TYPE_INFO;
seg.ls = prog.p_vaddr;
seg.addr = 0;
seg.size = prog.p_filesz;
}
else
{
LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type);
}
}
spu_ep = obj.header.e_entry;
sha1_finish(&ctx, output);
// Format patch name
@ -68,13 +103,36 @@ void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr)
}
}
u32 LoadSpuImage(const fs::file& stream, u32& spu_ep)
void sys_spu_image::free()
{
const u32 alloc_size = 256 * 1024;
u32 spu_offset = (u32)vm::alloc(alloc_size, vm::main);
if (type == SYS_SPU_IMAGE_TYPE_KERNEL)
{
vm::dealloc_verbose_nothrow(segs.addr(), vm::main);
}
}
LoadSpuImage(stream, spu_ep, spu_offset);
return spu_offset;
void sys_spu_image::deploy(u32 loc)
{
for (int i = 0; i < nsegs; i++)
{
auto& seg = segs[i];
LOG_NOTICE(SPU, "*** Deploy: t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", seg.type, seg.ls, seg.size, seg.addr);
if (seg.type == SYS_SPU_SEGMENT_TYPE_COPY)
{
std::memcpy(vm::base(loc + seg.ls), vm::base(seg.addr), seg.size);
}
else if (seg.type == SYS_SPU_SEGMENT_TYPE_FILL)
{
if ((seg.ls | seg.size) % 4)
{
LOG_ERROR(SPU, "Unaligned SPU FILL type segment (ls=0x%x, size=0x%x)", seg.ls, seg.size);
}
std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr);
}
}
}
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
@ -89,7 +147,7 @@ error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
return CELL_OK;
}
error_code sys_spu_image_open(vm::ptr<sys_spu_image_t> img, vm::cptr<char> path)
error_code sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
{
sys_spu.warning("sys_spu_image_open(img=*0x%x, path=%s)", img, path);
@ -101,18 +159,12 @@ error_code sys_spu_image_open(vm::ptr<sys_spu_image_t> img, vm::cptr<char> path)
return CELL_ENOENT;
}
u32 entry;
u32 offset = LoadSpuImage(elf_file, entry);
img->type = SYS_SPU_IMAGE_TYPE_USER;
img->entry_point = entry;
img->segs.set(offset); // TODO: writing actual segment info
img->nsegs = 1; // wrong value
img->load(elf_file);
return CELL_OK;
}
error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_num, vm::ptr<sys_spu_image_t> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg)
error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_num, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg)
{
sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg);
@ -151,7 +203,7 @@ error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_
group->threads[spu_num] = std::move(spu);
group->args[spu_num] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
group->images[spu_num] = img;
group->imgs[spu_num] = img;
if (++group->init == group->num)
{
@ -176,10 +228,7 @@ error_code sys_spu_thread_set_argument(u32 id, vm::ptr<sys_spu_thread_argument>
semaphore_lock lock(group->mutex);
group->args[thread->index].arg1 = arg->arg1;
group->args[thread->index].arg2 = arg->arg2;
group->args[thread->index].arg3 = arg->arg3;
group->args[thread->index].arg4 = arg->arg4;
group->args[thread->index] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
return CELL_OK;
}
@ -294,18 +343,16 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
if (thread)
{
auto& args = group->args[thread->index];
auto& image = group->images[thread->index];
auto& img = group->imgs[thread->index];
// Copy SPU image:
// TODO: use segment info
std::memcpy(vm::base(thread->offset), image->segs.get_ptr(), 256 * 1024);
img->deploy(thread->offset);
thread->pc = image->entry_point;
thread->pc = img->entry_point;
thread->cpu_init();
thread->gpr[3] = v128::from64(0, args.arg1);
thread->gpr[4] = v128::from64(0, args.arg2);
thread->gpr[5] = v128::from64(0, args.arg3);
thread->gpr[6] = v128::from64(0, args.arg4);
thread->gpr[3] = v128::from64(0, args[0]);
thread->gpr[4] = v128::from64(0, args[1]);
thread->gpr[5] = v128::from64(0, args[2]);
thread->gpr[6] = v128::from64(0, args[3]);
thread->status.exchange(SPU_STATUS_RUNNING);
}

View File

@ -88,7 +88,7 @@ struct sys_spu_segment
{
be_t<s32> type; // copy, fill, info
be_t<u32> ls; // local storage address
be_t<s32> size;
be_t<u32> size;
union
{
@ -105,12 +105,16 @@ enum : u32
SYS_SPU_IMAGE_TYPE_KERNEL = 1,
};
struct sys_spu_image_t
struct sys_spu_image
{
be_t<u32> type; // user, kernel
be_t<u32> entry_point;
vm::ps3::bptr<sys_spu_segment> segs;
be_t<s32> nsegs;
void load(const fs::file& stream);
void free();
void deploy(u32 loc);
};
enum : u32
@ -119,14 +123,6 @@ enum : u32
SYS_SPU_IMAGE_DIRECT = 1,
};
struct spu_arg_t
{
u64 arg1;
u64 arg2;
u64 arg3;
u64 arg4;
};
// SPU Thread Group Join State Flag
enum : u32
{
@ -157,8 +153,8 @@ struct lv2_spu_group
cond_variable cv; // used to signal waiting PPU thread
std::array<std::shared_ptr<SPUThread>, 256> threads; // SPU Threads
std::array<vm::ps3::ptr<sys_spu_image_t>, 256> images; // SPU Images
std::array<spu_arg_t, 256> args; // SPU Thread Arguments
std::array<vm::ps3::ptr<sys_spu_image>, 256> imgs; // SPU Images
std::array<std::array<u64, 4>, 256> args; // SPU Thread Arguments
std::weak_ptr<lv2_event_queue> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events
std::weak_ptr<lv2_event_queue> ep_exception; // TODO: SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION
@ -204,15 +200,11 @@ struct lv2_spu_group
class ppu_thread;
// Aux
void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr);
u32 LoadSpuImage(const fs::file& stream, u32& spu_ep);
// Syscalls
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
error_code sys_spu_image_open(vm::ps3::ptr<sys_spu_image_t> img, vm::ps3::cptr<char> path);
error_code sys_spu_thread_initialize(vm::ps3::ptr<u32> thread, u32 group, u32 spu_num, vm::ps3::ptr<sys_spu_image_t>, vm::ps3::ptr<sys_spu_thread_attribute>, vm::ps3::ptr<sys_spu_thread_argument>);
error_code sys_spu_image_open(vm::ps3::ptr<sys_spu_image> img, vm::ps3::cptr<char> path);
error_code sys_spu_thread_initialize(vm::ps3::ptr<u32> thread, u32 group, u32 spu_num, vm::ps3::ptr<sys_spu_image>, vm::ps3::ptr<sys_spu_thread_attribute>, vm::ps3::ptr<sys_spu_thread_argument>);
error_code sys_spu_thread_set_argument(u32 id, vm::ps3::ptr<sys_spu_thread_argument> arg);
error_code sys_spu_thread_group_create(vm::ps3::ptr<u32> id, u32 num, s32 prio, vm::ps3::ptr<sys_spu_thread_group_attribute> attr);
error_code sys_spu_thread_group_destroy(u32 id);