Exemple #1
0
s32 cellMusicInitialize2(s32 mode, s32 spuPriority, vm::ptr<CellMusic2Callback> func, vm::ptr<void> userData)
{
	cellMusic.Todo("cellMusicInitialize2(mode=%d, spuPriority=%d, func=*0x%x, userData=*0x%x)", mode, spuPriority, func, userData);

	if (mode != CELL_MUSIC2_PLAYER_MODE_NORMAL)
	{
		cellMusic.Todo("Unknown player mode: 0x%x", mode);
		return CELL_MUSIC2_ERROR_PARAM;
	}

	named_thread_t(WRAP_EXPR("CellMusicInit"), [=]()
	{
		const auto music = fxm::make_always<music2_t>();
		music->func = func;
		music->userData = userData;

		Emu.GetCallbackManager().Register([=](CPUThread& CPU) -> s32
		{
			vm::var<u32> ret(CPU);
			*ret = CELL_OK;
			func(static_cast<PPUThread&>(CPU), CELL_MUSIC2_EVENT_INITIALIZE_RESULT, ret, userData);
			return CELL_OK;
		});
	}).detach();

	return CELL_OK;
}
Exemple #2
0
void shared_mutex_t::lock()
{
	if (!try_lock())
	{
		std::unique_lock<std::mutex> lock(m_mutex);

		m_wwcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool
		{
			if (info.waiting_writers < UINT16_MAX)
			{
				info.waiting_writers++;
				return true;
			}

			return false;
		})));

		m_wcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool
		{
			if (!info.writers)
			{
				info.writers++;
				return true;
			}

			return false;
		})));

		m_wcv.wait(lock, WRAP_EXPR(m_info.load().readers == 0));

		const auto info = m_info.atomic_op([](ownership_info_t& info)
		{
			if (!info.waiting_writers--)
			{
				throw EXCEPTION("Invalid value");
			}
		});

		if (info.waiting_writers == UINT16_MAX)
		{
			m_wwcv.notify_one();
		}
	}
}
Exemple #3
0
SPUThread::SPUThread(const std::string& name, u32 index)
	: CPUThread(CPU_THREAD_SPU, name, WRAP_EXPR(fmt::format("SPU[0x%x] Thread (%s)[0x%05x]", m_id, m_name.c_str(), pc)))
	, index(index)
	, offset(vm::alloc(0x40000, vm::main))
{
	if (!offset)
	{
		throw EXCEPTION("Failed to allocate SPU local storage");
	}
}
Exemple #4
0
s32 cellFsAioWrite(vm::ptr<CellFsAio> aio, vm::ptr<s32> id, fs_aio_cb_t func)
{
	cellFs.Warning("cellFsAioWrite(aio=*0x%x, id=*0x%x, func=*0x%x)", aio, id, func);

	// TODO: detect mount point and send AIO request to the AIO thread of this mount point

	const s32 xid = (*id = ++g_fs_aio_id);

	named_thread_t(WRAP_EXPR("FS AIO Write Thread"), [=]{ fsAio(aio, true, xid, func); }).detach();

	return CELL_OK;
}
Exemple #5
0
u32 SPUThread::get_ch_value(u32 ch)
{
	if (Ini.HLELogging.GetValue())
	{
		LOG_NOTICE(SPU, "get_ch_value(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???");
	}

	auto read_channel = [this](spu_channel_t& channel) -> u32
	{
		std::unique_lock<std::mutex> lock(mutex, std::defer_lock);

		while (true)
		{
			bool result;
			u32 value;

			std::tie(result, value) = channel.try_pop();

			if (result)
			{
				return value;
			}

			CHECK_EMU_STATUS;

			if (is_stopped()) throw CPUThreadStop{};

			if (!lock)
			{
				lock.lock();
				continue;
			}

			cv.wait(lock);
		}
	};

	switch (ch)
	{
	//case SPU_RdSRR0:
	//	value = SRR0;
	//	break;
	case SPU_RdInMbox:
	{
		std::unique_lock<std::mutex> lock(mutex, std::defer_lock);

		while (true)
		{
			bool result;
			u32 value;
			u32 count;
			
			std::tie(result, value, count) = ch_in_mbox.try_pop();

			if (result)
			{
				if (count + 1 == 4 /* SPU_IN_MBOX_THRESHOLD */) // TODO: check this
				{
					int_ctrl[2].set(SPU_INT2_STAT_SPU_MAILBOX_THRESHOLD_INT);
				}

				return value;
			}

			CHECK_EMU_STATUS;

			if (is_stopped()) throw CPUThreadStop{};

			if (!lock)
			{
				lock.lock();
				continue;
			}

			cv.wait(lock);
		}
	}

	case MFC_RdTagStat:
	{
		return read_channel(ch_tag_stat);
	}

	case MFC_RdTagMask:
	{
		return ch_tag_mask;
	}

	case SPU_RdSigNotify1:
	{
		return read_channel(ch_snr1);
	}

	case SPU_RdSigNotify2:
	{
		return read_channel(ch_snr2);
	}

	case MFC_RdAtomicStat:
	{
		return read_channel(ch_atomic_stat);
	}

	case MFC_RdListStallStat:
	{
		return read_channel(ch_stall_stat);
	}

	case SPU_RdDec:
	{
		return ch_dec_value - (u32)(get_timebased_time() - ch_dec_start_timestamp);
	}

	case SPU_RdEventMask:
	{
		return ch_event_mask.load();
	}

	case SPU_RdEventStat:
	{
		std::unique_lock<std::mutex> lock(mutex, std::defer_lock);

		// start waiting or return immediately
		if (u32 res = get_events(true))
		{
			return res;
		}

		if (ch_event_mask.load() & SPU_EVENT_LR)
		{
			// register waiter if polling reservation status is required
			vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || is_stopped()));
		}
		else
		{
			lock.lock();

			// simple waiting loop otherwise
			while (!get_events(true) && !is_stopped())
			{
				CHECK_EMU_STATUS;

				cv.wait(lock);
			}
		}

		ch_event_stat &= ~SPU_EVENT_WAITING;

		if (is_stopped()) throw CPUThreadStop{};
		
		return get_events();
	}

	case SPU_RdMachStat:
	{
		// HACK: "Not isolated" status
		// Return SPU Interrupt status in LSB
		return (ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0;
	}
	}

	throw EXCEPTION("Unknown/illegal channel (ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???");
}
Exemple #6
0
s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam)
{
	cellSysutil.Warning("cellMsgDialogOpen2(type=0x%x, msgString=*0x%x, callback=*0x%x, userData=*0x%x, extParam=*0x%x)", type, msgString, callback, userData, extParam);

	if (!msgString || strlen(msgString.get_ptr()) >= 0x200 || type & -0x33f8)
	{
		return CELL_MSGDIALOG_ERROR_PARAM;
	}

	switch (type & CELL_MSGDIALOG_TYPE_BUTTON_TYPE)
	{
	case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE:
	{
		if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
		{
			return CELL_MSGDIALOG_ERROR_PARAM;
		}
		switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
		{
		case CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE: break;
		case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: break;
		case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: break;
		default: return CELL_MSGDIALOG_ERROR_PARAM;
		}
		break;
	}

	case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO:
	{
		switch (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
		{
		case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES: break;
		case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO: break;
		default: return CELL_MSGDIALOG_ERROR_PARAM;
		}
		if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
		{
			return CELL_MSGDIALOG_ERROR_PARAM;
		}
		break;
	}

	case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK:
	{
		if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
		{
			return CELL_MSGDIALOG_ERROR_PARAM;
		}
		if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
		{
			return CELL_MSGDIALOG_ERROR_PARAM;
		}
		break;
	}

	default: return CELL_MSGDIALOG_ERROR_PARAM;
	}

	MsgDialogState old = msgDialogNone;
	if (!g_msg_dialog->state.compare_exchange_strong(old, msgDialogInit))
	{
		return CELL_SYSUTIL_ERROR_BUSY;
	}

	g_msg_dialog->wait_until = get_system_time() + 31536000000000ull; // some big value

	switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
	{
	case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: g_msg_dialog->progress_bar_count = 2; break;
	case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: g_msg_dialog->progress_bar_count = 1; break;
	default: g_msg_dialog->progress_bar_count = 0; break;
	}

	switch (type & CELL_MSGDIALOG_TYPE_SE_MUTE) // TODO
	{
	case CELL_MSGDIALOG_TYPE_SE_MUTE_OFF: break;
	case CELL_MSGDIALOG_TYPE_SE_MUTE_ON: break;
	}

	std::string msg = msgString.get_ptr();

	switch (type & CELL_MSGDIALOG_TYPE_SE_TYPE)
	{
	case CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL: cellSysutil.Warning("%s", msg); break;
	case CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR: cellSysutil.Error("%s", msg); break;
	}

	g_msg_dialog->status = CELL_MSGDIALOG_BUTTON_NONE;

	CallAfter([type, msg]()
	{
		if (Emu.IsStopped())
		{
			g_msg_dialog->state.exchange(msgDialogNone);

			return;
		}

		g_msg_dialog->Create(type, msg);

		g_msg_dialog->state.exchange(msgDialogOpen);
	});

	while (g_msg_dialog->state == msgDialogInit)
	{
		if (Emu.IsStopped())
		{
			if (g_msg_dialog->state != msgDialogNone)
			{
				break;
			}

			CHECK_EMU_STATUS;
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
	}

	thread_t(WRAP_EXPR("MsgDialog Thread"), [=]()
	{
		while (g_msg_dialog->state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog->wait_until) < 0)
		{
			if (Emu.IsStopped())
			{
				g_msg_dialog->state = msgDialogAbort;
				break;
			}
			std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
		}

		if (callback && g_msg_dialog->state != msgDialogAbort)
		{
			const s32 status = g_msg_dialog->status;

			Emu.GetCallbackManager().Register([=](CPUThread& CPU) -> s32
			{
				callback(static_cast<PPUThread&>(CPU), status, userData);
				return CELL_OK;
			});
		}

		CallAfter([]()
		{
			g_msg_dialog->Destroy();
			g_msg_dialog->state = msgDialogNone;
		});

	}).detach();

	return CELL_OK;
}
Exemple #7
0
ARMv7Thread::ARMv7Thread(const std::string& name)
	: CPUThread(CPU_THREAD_ARMv7, name, WRAP_EXPR(fmt::format("ARMv7[0x%x] Thread (%s)[0x%08x]", m_id, m_name.c_str(), PC)))
	, ARMv7Context({})
{
}
Exemple #8
0
PPUThread::PPUThread(const std::string& name)
	: CPUThread(CPU_THREAD_PPU, name, WRAP_EXPR(fmt::format("PPU[0x%x] Thread (%s)[0x%08x]", m_id, m_name.c_str(), PC)))
{
	InitRotateMask();
}
Exemple #9
0
void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event))
{
	const bool was_running = Emu.Pause();

	wxFileDialog ctrl(this, L"Select PKG", wxEmptyString, wxEmptyString, "PKG files (*.pkg)|*.pkg|All files (*.*)|*.*", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
	
	if (ctrl.ShowModal() == wxID_CANCEL)
	{
		if (was_running) Emu.Resume();
		return;
	}

	Emu.Stop();

	Emu.GetVFS().Init("/");
	std::string local_path;
	Emu.GetVFS().GetDevice("/dev_hdd0/game/", local_path);

	// Open PKG file
	fs::file pkg_f(ctrl.GetPath().ToStdString());

	// Open file mapping (test)
	fs::file_ptr pkg_ptr(pkg_f);

	if (!pkg_f || !pkg_ptr)
	{
		LOG_ERROR(LOADER, "PKG: Failed to open %s", ctrl.GetPath().ToStdString());
		return;
	}

	// Append title ID to the path
	local_path += '/';
	local_path += { pkg_ptr + 55, 9 };

	if (!fs::create_dir(local_path))
	{
		if (fs::is_dir(local_path))
		{
			if (wxMessageDialog(this, "Another installation found. Do you want to overwrite it?", "PKG Decrypter / Installer", wxYES_NO | wxCENTRE).ShowModal() != wxID_YES)
			{
				LOG_ERROR(LOADER, "PKG: Cancelled installation to existing directory %s", local_path);
				return;
			}
		}
		else
		{
			LOG_ERROR(LOADER, "PKG: Could not create the installation directory %s", local_path);
			return;
		}
	}

	wxProgressDialog pdlg("PKG Decrypter / Installer", "Please wait, unpacking...", 1000, this, wxPD_AUTO_HIDE | wxPD_APP_MODAL);

	volatile f64 progress = 0.0;

	// Run PKG unpacking asynchronously
	auto result = std::async(std::launch::async, WRAP_EXPR(pkg_install(pkg_f, local_path + "/", progress)));

	// Wait for the completion
	while (result.wait_for(15ms) != std::future_status::ready)
	{
		// Update progress window
		pdlg.Update(progress * pdlg.GetRange());

		// Update main frame
		Update();
		wxGetApp().ProcessPendingEvents();
	}

	pdlg.Close();

	if (result.get())
	{
		LOG_SUCCESS(LOADER, "PKG: Package successfully installed in %s", local_path);

		// Refresh game list
		m_game_viewer->Refresh();
	}
}