/** * Parse attribute AS_PATH data * * \param [in] attr_len Length of the attribute data * \param [in] data Pointer to the attribute data * \param [out] parsed_update Reference to parsed_update; will be updated with all parsed data */ void parseBgpLib::parseAttrDataAsPath(uint16_t attr_len, u_char *data, parsed_update &update) { int path_len = attr_len; u_char seg_type; u_char seg_len; uint32_t seg_asn; uint32_t origin_asn = -1; if (path_len < 4) // Nothing to parse if length doesn't include at least one asn return; update.attrs[LIB_ATTR_AS_PATH].official_type = ATTR_TYPE_AS_PATH; update.attrs[LIB_ATTR_AS_PATH].name = parse_bgp_lib::parse_bgp_lib_attr_names[LIB_ATTR_AS_PATH]; /* * Per draft-ietf-grow-bmp, UPDATES must be sent as 4-octet, but this requires the * UPDATE to be modified. In draft 14 a new peer header flag indicates size, but * not all implementations support this draft yet. * * IOS XE/XR does not modify the UPDATE and therefore a peers * that is using 2-octet ASN's will not be parsed correctly. Global instance var * four_octet_asn is used to check if the OPEN cap sent/recv 4-octet or not. A compliant * BMP implementation will still use 4-octet even if the peer is 2-octet, so a check is * needed to see if the as path is encoded using 4 or 2 octet. This check is only done * once. * * This is temporary and can be removed after all implementations are complete with bmp draft 14 or greater. */ if (p_info and not p_info->checked_asn_octet_length and not four_octet_asn) { /* * Loop through each path segment */ u_char *d_ptr = data; while (path_len > 0) { d_ptr++; // seg_type seg_len = *d_ptr++; path_len -= 2 + (seg_len * 4); if (path_len >= 0) d_ptr += seg_len * 4; } if (path_len != 0) { LOG_INFO("%sUsing 2-octet ASN path parsing", debug_prepend_string.c_str()); p_info->using_2_octet_asn = true; } p_info->checked_asn_octet_length = true; // No more checking needed path_len = attr_len; // Put the path length back to starting value } // Define the octet size by known/detected size if (p_info) asn_octet_size = (p_info->using_2_octet_asn and not four_octet_asn) ? 2 : 4; /* * Loop through each path segment */ while (path_len > 0) { seg_type = *data++; seg_len = *data++; // Count of AS's, not bytes path_len -= 2; std::string decoded_path; if (seg_type == 1) { // If AS-SET open with a brace decoded_path.append(" {"); } SELF_DEBUG("%sas_path seg_len = %d seg_type = %d, path_len = %d total_len = %d as_octet_size = %d", debug_prepend_string.c_str(), seg_len, seg_type, path_len, attr_len, asn_octet_size); if ((seg_len * asn_octet_size) > path_len){ LOG_NOTICE("%sCould not parse the AS PATH due to update message buffer being too short when using ASN octet size %d", debug_prepend_string.c_str(), asn_octet_size); LOG_NOTICE("%sSwitching encoding size to 2-octet due to parsing failure", debug_prepend_string.c_str()); asn_octet_size = 2; } // The rest of the data is the as path sequence, in blocks of 2 or 4 bytes for (; seg_len > 0; seg_len--) { seg_asn = 0; memcpy(&seg_asn, data, asn_octet_size); data += asn_octet_size; path_len -= asn_octet_size; // Adjust the path length for what was read parse_bgp_lib::SWAP_BYTES(&seg_asn, asn_octet_size); std::ostringstream numString; numString << seg_asn; if (seg_type == 2) { update.attrs[LIB_ATTR_AS_PATH].value.push_back(numString.str()); origin_asn = seg_asn; } else if (seg_type == 1) { decoded_path.append(", "); decoded_path.append(numString.str()); } else { std::cout << "Malformed AS path segment of type: " << static_cast<int>(seg_type) <<std::endl; } } if (seg_type == 1) { // If AS-SET close with a brace decoded_path.append(" }"); update.attrs[LIB_ATTR_AS_PATH].value.push_back(decoded_path); } } if (origin_asn >= 0) { update.attrs[LIB_ATTR_AS_ORIGIN].name = parse_bgp_lib::parse_bgp_lib_attr_names[LIB_ATTR_AS_ORIGIN]; std::ostringstream numString; numString << origin_asn; update.attrs[LIB_ATTR_AS_ORIGIN].value.push_back(numString.str()); } SELF_DEBUG("%sParsed AS_PATH count %d, origin as: %s", debug_prepend_string.c_str(), update.attrs[LIB_ATTR_AS_PATH].value.size(), update.attrs[LIB_ATTR_AS_PATH].value.size() > 0 ? update.attrs[LIB_ATTR_AS_PATH].value.front().c_str() : "NULL"); }
void Emulator::Load() { Stop(); try { Init(); // Open SELF or ELF fs::file elf_file(m_path); if (!elf_file) { LOG_ERROR(LOADER, "Failed to open file: %s", m_path); return; } LOG_NOTICE(LOADER, "Path: %s", m_path); const std::string elf_dir = fs::get_parent_dir(m_path); const fs::file sfov(elf_dir + "/sce_sys/param.sfo"); const fs::file sfo1(elf_dir + "/../PARAM.SFO"); // Load PARAM.SFO (TODO) const auto _psf = psf::load_object(sfov ? sfov : sfo1); m_title = psf::get_string(_psf, "TITLE", m_path); m_title_id = psf::get_string(_psf, "TITLE_ID"); LOG_NOTICE(LOADER, "Title: %s", GetTitle()); LOG_NOTICE(LOADER, "Serial: %s", GetTitleID()); // Initialize data/cache directory m_cache_path = fs::get_data_dir(m_title_id, m_path); LOG_NOTICE(LOADER, "Cache: %s", GetCachePath()); // Load custom config-0 if (fs::file cfg_file{m_cache_path + "/config.yml"}) { LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path); g_cfg.from_string(cfg_file.to_string()); } // Load custom config-1 if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"}) { LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id); g_cfg.from_string(cfg_file.to_string()); } // Load custom config-2 if (fs::file cfg_file{m_path + ".yml"}) { LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path); g_cfg.from_string(cfg_file.to_string()); } LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string()); // Load patches from different locations fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml"); fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml"); // Mount all devices const std::string emu_dir_ = g_cfg.vfs.emulator_dir; const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_; const std::string home_dir = g_cfg.vfs.app_home; std::string bdvd_dir = g_cfg.vfs.dev_bdvd; vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir)); vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir)); // Mount /dev_bdvd/ if necessary if (bdvd_dir.empty()) { size_t pos = elf_dir.rfind("PS3_GAME"); std::string temp = elf_dir.substr(0, pos); if ((pos != std::string::npos) && fs::is_file(temp + "/PS3_DISC.SFB")) { bdvd_dir = temp; } } if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir)) { vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir)); LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd")); } // Mount /host_root/ if necessary if (g_cfg.vfs.host_root) { vfs::mount("host_root", {}); } // Check SELF header if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32) { const std::string decrypted_path = m_cache_path + "boot.elf"; fs::stat_t encrypted_stat = elf_file.stat(); fs::stat_t decrypted_stat; // Check modification time and try to load decrypted ELF if (fs::stat(decrypted_path, decrypted_stat) && decrypted_stat.mtime == encrypted_stat.mtime) { elf_file.open(decrypted_path); } else { // Decrypt SELF elf_file = decrypt_self(std::move(elf_file)); if (fs::file elf_out{decrypted_path, fs::rewrite}) { elf_out.write(elf_file.to_vector<u8>()); elf_out.close(); fs::utime(decrypted_path, encrypted_stat.atime, encrypted_stat.mtime); } else { LOG_ERROR(LOADER, "Failed to create boot.elf"); } } } ppu_exec_object ppu_exec; ppu_prx_object ppu_prx; spu_exec_object spu_exec; arm_exec_object arm_exec; if (!elf_file) { LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path); return; } else if (ppu_exec.open(elf_file) == elf_error::ok) { // PS3 executable g_system = system_type::ps3; m_state = system_state::ready; GetCallbacks().on_ready(); vm::ps3::init(); if (m_elf_path.empty()) { if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir)) { //Disc games are on /dev_bdvd/ size_t pos = m_path.rfind("PS3_GAME"); m_elf_path = "/dev_bdvd/" + m_path.substr(pos); } else if (m_path.find(vfs::get("/dev_hdd0/game/")) != -1) { m_elf_path = "/dev_hdd0/game/" + m_path.substr(vfs::get("/dev_hdd0/game/").size()); } else { //For homebrew m_elf_path = "/host_root/" + m_path; } LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); } ppu_load_exec(ppu_exec); fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall } else if (ppu_prx.open(elf_file) == elf_error::ok) { // PPU PRX (experimental) g_system = system_type::ps3; m_state = system_state::ready; GetCallbacks().on_ready(); vm::ps3::init(); ppu_load_prx(ppu_prx, ""); } else if (spu_exec.open(elf_file) == elf_error::ok) { // SPU executable (experimental) g_system = system_type::ps3; m_state = system_state::ready; GetCallbacks().on_ready(); vm::ps3::init(); spu_load_exec(spu_exec); } else if (arm_exec.open(elf_file) == elf_error::ok) { // ARMv7 executable g_system = system_type::psv; m_state = system_state::ready; GetCallbacks().on_ready(); vm::psv::init(); if (m_elf_path.empty()) { m_elf_path = "host_root:" + m_path; LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); } arm_load_exec(arm_exec); } else { LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path); LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error()); LOG_WARNING(LOADER, "** ppu_prx -> %s", ppu_prx.get_error()); LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error()); LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error()); return; } if (g_cfg.misc.autostart && IsReady()) { Run(); } else if (IsPaused()) { m_state = system_state::ready; GetCallbacks().on_ready(); } } catch (const std::exception& e) { LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what()); Stop(); } }
void Emulator::Load(bool add_only) { Stop(); try { Init(); // Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations) YAML::Node games = YAML::Load(fs::file{fs::get_config_dir() + "/games.yml", fs::read + fs::create}.to_string()); if (!games.IsMap()) { games.reset(); } LOG_NOTICE(LOADER, "Path: %s", m_path); const std::string elf_dir = fs::get_parent_dir(m_path); // Load PARAM.SFO (TODO) const auto _psf = psf::load_object([&] { if (fs::file sfov{elf_dir + "/sce_sys/param.sfo"}) { return sfov; } else { return fs::file(elf_dir + "/../PARAM.SFO"); } }()); m_title = psf::get_string(_psf, "TITLE", m_path); m_title_id = psf::get_string(_psf, "TITLE_ID"); const auto _cat = psf::get_string(_psf, "CATEGORY"); LOG_NOTICE(LOADER, "Title: %s", GetTitle()); LOG_NOTICE(LOADER, "Serial: %s", GetTitleID()); // Initialize data/cache directory m_cache_path = fs::get_data_dir(m_title_id, m_path); LOG_NOTICE(LOADER, "Cache: %s", GetCachePath()); // Load custom config-0 if (fs::file cfg_file{m_cache_path + "/config.yml"}) { LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path); g_cfg.from_string(cfg_file.to_string()); } // Load custom config-1 if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"}) { LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id); g_cfg.from_string(cfg_file.to_string()); } // Load custom config-2 if (fs::file cfg_file{m_path + ".yml"}) { LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path); g_cfg.from_string(cfg_file.to_string()); } LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string()); // Load patches from different locations fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml"); fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml"); // Mount all devices const std::string emu_dir_ = g_cfg.vfs.emulator_dir; const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_; const std::string home_dir = g_cfg.vfs.app_home; std::string bdvd_dir = g_cfg.vfs.dev_bdvd; vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir)); vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir)); vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir)); // Detect boot location const std::string hdd0_game = vfs::get("/dev_hdd0/game/"); const std::string hdd0_disc = vfs::get("/dev_hdd0/disc/"); if (_cat == "DG" && m_path.find(hdd0_game + m_title_id + '/') != -1) { // Booting disc game from wrong location LOG_ERROR(LOADER, "Disc game found at invalid location: /dev_hdd0/game/%s/", m_title_id); // Move and retry from correct location if (fs::rename(hdd0_game + m_title_id, hdd0_disc + m_title_id)) { LOG_SUCCESS(LOADER, "Disc game moved to special location: /dev_hdd0/disc/%s/", m_title_id); return SetPath(hdd0_disc + m_path.substr(hdd0_game.size())), Load(); } else { LOG_ERROR(LOADER, "Failed to move disc game to /dev_hdd0/disc/%s/ (%s)", m_title_id, fs::g_tls_error); return; } } // Booting disc game if (_cat == "DG" && bdvd_dir.empty()) { // Mount /dev_bdvd/ if necessary if (auto pos = elf_dir.rfind("/PS3_GAME") + 1) { bdvd_dir = elf_dir.substr(0, pos); } } // Booting patch data if (_cat == "GD" && bdvd_dir.empty()) { // Load /dev_bdvd/ from game list if available if (auto node = games[m_title_id]) { bdvd_dir = node.Scalar(); } else { LOG_FATAL(LOADER, "Disc directory not found. Try to run the game from the actual game disc directory."); } } // Check /dev_bdvd/ if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir)) { fs::file sfb_file; vfs::mount("dev_bdvd", bdvd_dir); LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd")); if (!sfb_file.open(vfs::get("/dev_bdvd/PS3_DISC.SFB")) || sfb_file.size() < 4 || sfb_file.read<u32>() != ".SFB"_u32) { LOG_ERROR(LOADER, "Invalid disc directory for the disc game %s", m_title_id); return; } const std::string bdvd_title_id = psf::get_string(psf::load_object(fs::file{vfs::get("/dev_bdvd/PS3_GAME/PARAM.SFO")}), "TITLE_ID"); if (bdvd_title_id != m_title_id) { LOG_ERROR(LOADER, "Unexpected disc directory for the disc game %s (found %s)", m_title_id, bdvd_title_id); return; } // Store /dev_bdvd/ location games[m_title_id] = bdvd_dir; YAML::Emitter out; out << games; fs::file(fs::get_config_dir() + "/games.yml", fs::rewrite).write(out.c_str(), out.size()); } else if (_cat == "DG" || _cat == "GD") { LOG_ERROR(LOADER, "Failed to mount disc directory for the disc game %s", m_title_id); return; } if (add_only) { LOG_NOTICE(LOADER, "Finished to add data to games.yml by boot for: %s", m_path); return; } // Check game updates const std::string hdd0_boot = hdd0_game + m_title_id + "/USRDIR/EBOOT.BIN"; if (_cat == "DG" && fs::is_file(hdd0_boot)) { // Booting game update LOG_SUCCESS(LOADER, "Updates found at /dev_hdd0/game/%s/!", m_title_id); return SetPath(hdd0_boot), Load(); } // Mount /host_root/ if necessary if (g_cfg.vfs.host_root) { vfs::mount("host_root", {}); } // Open SELF or ELF fs::file elf_file(m_path); if (!elf_file) { LOG_ERROR(LOADER, "Failed to open executable: %s", m_path); return; } // Check SELF header if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32) { const std::string decrypted_path = m_cache_path + "boot.elf"; fs::stat_t encrypted_stat = elf_file.stat(); fs::stat_t decrypted_stat; // Check modification time and try to load decrypted ELF if (fs::stat(decrypted_path, decrypted_stat) && decrypted_stat.mtime == encrypted_stat.mtime) { elf_file.open(decrypted_path); } else { // Decrypt SELF elf_file = decrypt_self(std::move(elf_file)); if (fs::file elf_out{decrypted_path, fs::rewrite}) { elf_out.write(elf_file.to_vector<u8>()); elf_out.close(); fs::utime(decrypted_path, encrypted_stat.atime, encrypted_stat.mtime); } else { LOG_ERROR(LOADER, "Failed to create boot.elf"); } } } ppu_exec_object ppu_exec; ppu_prx_object ppu_prx; spu_exec_object spu_exec; arm_exec_object arm_exec; if (!elf_file) { LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path); return; } else if (ppu_exec.open(elf_file) == elf_error::ok) { // PS3 executable g_system = system_type::ps3; m_state = system_state::ready; GetCallbacks().on_ready(); vm::ps3::init(); if (m_elf_path.empty()) { if (m_path.find(hdd0_game) != -1) { m_elf_path = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size()); } else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir)) { //Disc games are on /dev_bdvd/ size_t pos = m_path.rfind("PS3_GAME"); m_elf_path = "/dev_bdvd/" + m_path.substr(pos); } else { //For homebrew m_elf_path = "/host_root/" + m_path; } LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); } ppu_load_exec(ppu_exec); fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall } else if (ppu_prx.open(elf_file) == elf_error::ok) { // PPU PRX (experimental) g_system = system_type::ps3; m_state = system_state::ready; GetCallbacks().on_ready(); vm::ps3::init(); ppu_load_prx(ppu_prx, m_path); } else if (spu_exec.open(elf_file) == elf_error::ok) { // SPU executable (experimental) g_system = system_type::ps3; m_state = system_state::ready; GetCallbacks().on_ready(); vm::ps3::init(); spu_load_exec(spu_exec); } else if (arm_exec.open(elf_file) == elf_error::ok) { // ARMv7 executable g_system = system_type::psv; m_state = system_state::ready; GetCallbacks().on_ready(); vm::psv::init(); if (m_elf_path.empty()) { m_elf_path = "host_root:" + m_path; LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); } arm_load_exec(arm_exec); } else { LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path); LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error()); LOG_WARNING(LOADER, "** ppu_prx -> %s", ppu_prx.get_error()); LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error()); LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error()); return; } if (g_cfg.misc.autostart && IsReady()) { Run(); } else if (IsPaused()) { m_state = system_state::ready; GetCallbacks().on_ready(); } } catch (const std::exception& e) { LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what()); Stop(); } }
void ControlInfo::Show() { LOG_NOTICE(LOADER, "Type: 0x%08x", type); LOG_NOTICE(LOADER, "Size: 0x%08x", size); LOG_NOTICE(LOADER, "Next: 0x%llx", next); if (type == 1) { LOG_NOTICE(LOADER, "Control flag 1: 0x%08x", control_flags.ctrl_flag1); LOG_NOTICE(LOADER, "Unknown1: 0x%08x", control_flags.unknown1); LOG_NOTICE(LOADER, "Unknown2: 0x%08x", control_flags.unknown2); LOG_NOTICE(LOADER, "Unknown3: 0x%08x", control_flags.unknown3); LOG_NOTICE(LOADER, "Unknown4: 0x%08x", control_flags.unknown4); LOG_NOTICE(LOADER, "Unknown5: 0x%08x", control_flags.unknown5); LOG_NOTICE(LOADER, "Unknown6: 0x%08x", control_flags.unknown6); LOG_NOTICE(LOADER, "Unknown7: 0x%08x", control_flags.unknown7); } else if (type == 2) { if (size == 0x30) { std::string digest_str; for (int i = 0; i < 20; i++) digest_str += fmt::format("%02x", file_digest_30.digest[i]); LOG_NOTICE(LOADER, "Digest: %s", digest_str.c_str()); LOG_NOTICE(LOADER, "Unknown: 0x%llx", file_digest_30.unknown); } else if (size == 0x40) { std::string digest_str1; std::string digest_str2; for (int i = 0; i < 20; i++) { digest_str1 += fmt::format("%02x", file_digest_40.digest1[i]); digest_str2 += fmt::format("%02x", file_digest_40.digest2[i]); } LOG_NOTICE(LOADER, "Digest1: %s", digest_str1.c_str()); LOG_NOTICE(LOADER, "Digest2: %s", digest_str2.c_str()); LOG_NOTICE(LOADER, "Unknown: 0x%llx", file_digest_40.unknown); } } else if (type == 3) { std::string contentid_str; std::string digest_str; std::string invdigest_str; std::string xordigest_str; for (int i = 0; i < 48; i++) contentid_str += fmt::format("%02x", npdrm.content_id[i]); for (int i = 0; i < 16; i++) { digest_str += fmt::format("%02x", npdrm.digest[i]); invdigest_str += fmt::format("%02x", npdrm.invdigest[i]); xordigest_str += fmt::format("%02x", npdrm.xordigest[i]); } LOG_NOTICE(LOADER, "Magic: 0x%08x", npdrm.magic); LOG_NOTICE(LOADER, "Unknown1: 0x%08x", npdrm.unknown1); LOG_NOTICE(LOADER, "License: 0x%08x", npdrm.license); LOG_NOTICE(LOADER, "Type: 0x%08x", npdrm.type); LOG_NOTICE(LOADER, "ContentID: %s", contentid_str.c_str()); LOG_NOTICE(LOADER, "Digest: %s", digest_str.c_str()); LOG_NOTICE(LOADER, "Inverse digest: %s", invdigest_str.c_str()); LOG_NOTICE(LOADER, "XOR digest: %s", xordigest_str.c_str()); LOG_NOTICE(LOADER, "Unknown2: 0x%llx", npdrm.unknown2); LOG_NOTICE(LOADER, "Unknown3: 0x%llx", npdrm.unknown3); } }
void CPUThread::Task() { if (Ini.HLELogging.GetValue()) LOG_NOTICE(PPU, "%s enter", CPUThread::GetFName().c_str()); const std::vector<u64>& bp = Emu.GetBreakPoints(); for (uint i = 0; i<bp.size(); ++i) { if (bp[i] == m_offset + PC) { Emu.Pause(); break; } } std::vector<u64> trace; #ifdef _WIN32 _set_se_translator(_se_translator); #else // TODO: linux version #endif while (true) { int status = ThreadStatus(); if (status == CPUThread_Stopped || status == CPUThread_Break) { break; } if (status == CPUThread_Sleeping) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } Step(); //if (PC - 0x13ED4 < 0x288) trace.push_back(PC); NextPc(m_dec->DecodeMemory(PC + m_offset)); if (status == CPUThread_Step) { m_is_step = false; break; } for (uint i = 0; i < bp.size(); ++i) { if (bp[i] == PC) { Emu.Pause(); break; } } } for (auto& v : trace) LOG_NOTICE(PPU, "PC = 0x%llx", v); if (Ini.HLELogging.GetValue()) LOG_NOTICE(PPU, "%s leave", CPUThread::GetFName().c_str()); }
u8 edid_EventHandler(u16 baseAddr, int hpd, u8 state) { LOG_TRACE2(hpd, state); if (edid_mStatus != EDID_READING) { return EDID_IDLE; } else if (!hpd) { /* hot plug detected without cable disconnection */ error_Set(ERR_HPD_LOST); LOG_WARNING("hpd"); edid_mStatus = EDID_ERROR; } else if ((state & BIT(0)) != 0) /* error */ { LOG_WARNING("error"); edid_mStatus = EDID_ERROR; } else if ((state & BIT(1)) != 0) /* done */ { if (edid_mCurrAddress >= sizeof(edid_mBuffer)) { error_Set(ERR_OVERFLOW); LOG_WARNING("overflow"); edid_mStatus = EDID_ERROR; } else { edid_mBuffer[edid_mCurrAddress] = halEdid_ReadData(baseAddr + I2CM_BASE_ADDR); edid_mBlockSum += edid_mBuffer[edid_mCurrAddress++]; if (edid_mCurrAddress >= sizeof(edid_mBuffer)) { /*check if checksum is correct (CEA-861 D Spec p108) */ if (edid_mBlockSum % 0x100 == 0) { LOG_NOTICE("block checksum correct"); edid_ParseBlock(baseAddr, edid_mBuffer); edid_mCurrAddress = 0; edid_mCurrBlockNo++; edid_mBlockSum = 0; if (edid_mCurrBlockNo >= edid_mBlocksNo) { edid_mStatus = EDID_DONE; } } else { error_Set(ERR_BLOCK_CHECKSUM_INVALID); LOG_WARNING("block checksum invalid"); edid_mStatus = EDID_ERROR; } } } } if (edid_mStatus == EDID_READING) { edid_ReadRequest(baseAddr, edid_mCurrAddress, edid_mCurrBlockNo); } else if (edid_mStatus == EDID_DONE) { edid_mBlocksNo = 1; edid_mCurrBlockNo = 0; edid_mCurrAddress = 0; edid_mBlockSum = 0; } return edid_mStatus; }
s32 sys_ppu_thread_create(mem64_t thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, u32 threadname_addr) { std::string threadname = ""; if (Memory.IsGoodAddr(threadname_addr)) { threadname = Memory.ReadString(threadname_addr); sysPrxForUser->Log("sys_ppu_thread_create(thread_id_addr=0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x('%s'))", thread_id.GetAddr(), entry, arg, prio, stacksize, flags, threadname_addr, threadname.c_str()); } else { sysPrxForUser->Log("sys_ppu_thread_create(thread_id_addr=0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x)", thread_id.GetAddr(), entry, arg, prio, stacksize, flags, threadname_addr); if (threadname_addr != 0) return CELL_EFAULT; } if (!Memory.IsGoodAddr(entry) || !thread_id.IsGood()) { return CELL_EFAULT; } bool is_joinable = false; bool is_interrupt = false; switch (flags) { case 0: break; case SYS_PPU_THREAD_CREATE_JOINABLE: { is_joinable = true; break; } case SYS_PPU_THREAD_CREATE_INTERRUPT: { is_interrupt = true; break; } default: sysPrxForUser->Error("sys_ppu_thread_create(): unknown flags value (0x%llx)", flags); return CELL_EPERM; } CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU); thread_id = new_thread.GetId(); new_thread.SetEntry(entry); new_thread.SetArg(0, arg); new_thread.SetPrio(prio); new_thread.SetStackSize(stacksize); //new_thread.flags = flags; new_thread.m_has_interrupt = false; new_thread.m_is_interrupt = is_interrupt; new_thread.SetName(threadname); LOG_NOTICE(PPU, "*** New PPU Thread [%s] (flags=0x%llx, entry=0x%x): id = %d", new_thread.GetName().c_str(), flags, entry, new_thread.GetId()); if (!is_interrupt) { new_thread.Run(); new_thread.Exec(); } return CELL_OK; }
bool extract_all_data(const fs::file* input, const fs::file* output, const char* input_file_name, unsigned char* devklic, unsigned char* rifkey, bool verbose) { // Setup NPD and EDAT/SDAT structs. NPD_HEADER NPD; EDAT_HEADER EDAT; // Read in the NPD and EDAT/SDAT headers. read_npd_edat_header(input, NPD, EDAT); unsigned char npd_magic[4] = {0x4E, 0x50, 0x44, 0x00}; //NPD0 if (memcmp(&NPD.magic, npd_magic, 4)) { LOG_ERROR(LOADER, "EDAT: %s has invalid NPD header or already decrypted.", input_file_name); return 1; } if (verbose) { LOG_NOTICE(LOADER, "NPD HEADER"); LOG_NOTICE(LOADER, "NPD version: %d", NPD.version); LOG_NOTICE(LOADER, "NPD license: %d", NPD.license); LOG_NOTICE(LOADER, "NPD type: %d", NPD.type); } // Set decryption key. u8 key[0x10] = { 0 }; // Check EDAT/SDAT flag. if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG) { if (verbose) { LOG_NOTICE(LOADER, "SDAT HEADER"); LOG_NOTICE(LOADER, "SDAT flags: 0x%08X", EDAT.flags); LOG_NOTICE(LOADER, "SDAT block size: 0x%08X", EDAT.block_size); LOG_NOTICE(LOADER, "SDAT file size: 0x%08X", (u64)EDAT.file_size); } // Generate SDAT key. xor_key(key, NPD.dev_hash, SDAT_KEY); } else { if (verbose) { LOG_NOTICE(LOADER, "EDAT HEADER"); LOG_NOTICE(LOADER, "EDAT flags: 0x%08X", EDAT.flags); LOG_NOTICE(LOADER, "EDAT block size: 0x%08X", EDAT.block_size); LOG_NOTICE(LOADER, "EDAT file size: 0x%08X", (u64)EDAT.file_size); } // Perform header validation (EDAT only). char real_file_name[MAX_PATH]; extract_file_name(input_file_name, real_file_name); if (!validate_npd_hashes(real_file_name, devklic, &NPD, verbose)) { // Ignore header validation in DEBUG data. if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG) { LOG_ERROR(LOADER, "EDAT: NPD hash validation failed!"); return 1; } } // Select EDAT key. if ((NPD.license & 0x3) == 0x3) // Type 3: Use supplied devklic. memcpy(key, devklic, 0x10); else if ((NPD.license & 0x2) == 0x2) // Type 2: Use key from RAP file (RIF key). { memcpy(key, rifkey, 0x10); // Make sure we don't have an empty RIF key. int i, test = 0; for (i = 0; i < 0x10; i++) { if (key[i] != 0) { test = 1; break; } } if (!test) { LOG_ERROR(LOADER, "EDAT: A valid RAP file is needed for this EDAT file!"); return 1; } } else if ((NPD.license & 0x1) == 0x1) // Type 1: Use network activation. { LOG_ERROR(LOADER, "EDAT: Network license not supported!"); return 1; } if (verbose) { int i; LOG_NOTICE(LOADER, "DEVKLIC: "); for (i = 0; i < 0x10; i++) LOG_NOTICE(LOADER, "%02X", devklic[i]); LOG_NOTICE(LOADER, "RIF KEY: "); for (i = 0; i < 0x10; i++) LOG_NOTICE(LOADER, "%02X", rifkey[i]); } } if (verbose) { int i; LOG_NOTICE(LOADER, "DECRYPTION KEY: "); for (i = 0; i < 0x10; i++) LOG_NOTICE(LOADER, "%02X", key[i]); } input->seek(0); if (check_data(key, &EDAT, &NPD, input, verbose)) { LOG_ERROR(LOADER, "EDAT: Data parsing failed!"); return 1; } input->seek(0); if (decrypt_data(input, output, &EDAT, &NPD, key, verbose)) { LOG_ERROR(LOADER, "EDAT: Data decryption failed!"); return 1; } return 0; }
int LsapiConn::processRespBuffed() { int ret; int left; int len; m_pRespHeader = (char *)&m_respHeader; m_pRespHeaderBufEnd = &m_respBuf[1024]; ret = read( m_pRespHeader, m_pRespHeaderBufEnd - m_pRespHeader ); if ( ret <= 0 ) return ret; if ( ret < (int)sizeof( lsapi_packet_header ) ) { m_iPacketHeaderLeft = sizeof( lsapi_packet_header ) - ret; return ret; } m_pRespHeaderBufEnd = m_pRespHeader + ret; m_iPacketLeft = verifyPacketHeader( &m_respHeader ) - LSAPI_PACKET_HEADER_LEN; if ( m_iPacketLeft < 0 ) { errno = EIO; return -1; } if ( !m_iPacketLeft ) m_iPacketHeaderLeft = LSAPI_PACKET_HEADER_LEN; else m_iPacketHeaderLeft = 0; if ( ret < (int)(sizeof( lsapi_packet_header ) + sizeof( lsapi_resp_info )) ) { m_pRespHeader += ret; switch( m_respHeader.m_type ) { case LSAPI_RESP_END: m_respState = LSAPI_CONN_IDLE; incReqProcessed(); setInProcess( 0 ); getConnector()->endResponse( 0, 0 ); return 0; case LSAPI_RESP_HEADER: m_iCurRespHeader = 0; m_respState = LSAPI_CONN_READ_RESP_INFO; m_pRespHeaderProcess = (char *)&m_respInfo; setRespBuf( m_pRespHeaderProcess ); return ret; case LSAPI_REQ_RECEIVED: m_reqReceived = 1; break; } m_pRespHeaderProcess = (char *)&m_respInfo; } else { m_iCurRespHeader = 0; m_respState = LSAPI_CONN_READ_HEADER_LEN; m_pRespHeaderProcess = m_respBuf; } while( (left = m_pRespHeaderBufEnd - m_pRespHeaderProcess) > 0 ) { if ( m_iPacketHeaderLeft > 0 ) { ret = processPacketHeader( m_pRespHeaderProcess, left ); if ( ret <= 0 ) return ret; m_pRespHeaderProcess += ret; left -= ret; } if ( m_iPacketLeft > 0 ) { register HttpExtConnector * pHEC = getConnector(); if ( !pHEC ) return -1; int &respState = pHEC->getRespState(); if ( m_iPacketLeft < left ) { len = m_iPacketLeft; m_iPacketLeft = 0; m_iPacketHeaderLeft = LSAPI_PACKET_HEADER_LEN; } else { len = left; m_iPacketLeft -= left; left = 0; } switch( m_respHeader.m_type ) { case LSAPI_RESP_HEADER: ret = processRespHeader(m_pRespHeaderBufEnd, respState); if ( ret < 0 ) return ret; break; case LSAPI_RESP_STREAM: if ( D_ENABLED( DL_MEDIUM ) ) LOG_D(( getLogger(), "[%s] process response stream %d bytes", getLogId(), len )); ret = pHEC->processRespData( m_pRespHeaderProcess, len ); if ( respState & 0xff ) m_respState = LSAPI_CONN_READ_RESP_BODY; if ( ret == -1 ) return ret; m_pRespHeaderProcess += len; break; case LSAPI_STDERR_STREAM: if ( D_ENABLED( DL_MEDIUM ) ) LOG_D(( getLogger(), "[%s] process STDERR stream %d bytes", getLogId(), len )); ret = pHEC->processErrData( m_pRespHeaderProcess, len ); m_pRespHeaderProcess += len; break; default: LOG_NOTICE(( getLogger(), "[%s] Unknown Packet Type %c, LSAPI protcol is broken.", getLogId(), m_respHeader.m_type )); errno = EIO; return -1; } } else m_iPacketHeaderLeft = LSAPI_PACKET_HEADER_LEN; } return 1; }
/** * Parses the BGP attributes in the update * * \details * Parses all attributes. Decoded values are updated in 'parsed_data' * * \param [in] data Pointer to the start of the prefixes to be parsed * \param [in] len Length of the data in bytes to be read * \param [out] parsed_update Reference to parsed_update; will be updated with all parsed data */ void parseBgpLib::parseBgpAttr(u_char *data, uint16_t len, parsed_update &update) { /* * Per RFC4271 Section 4.3, flag indicates if the length is 1 or 2 octets */ u_char attr_flags; u_char attr_type; uint16_t attr_len; if (len == 0) return; else if (len < 3) { LOG_WARN("%sCannot parse the attributes due to the data being too short, error in update message. len=%d", debug_prepend_string.c_str(), len); return; } // Generate the hash MD5 hash; /* * Iterate through all attributes and parse them */ for (int read_size = 0; read_size < len; read_size += 2) { attr_flags = *data++; attr_type = *data++; // Check if the length field is 1 or two bytes if (ATTR_FLAG_EXTENDED(attr_flags)) { SELF_DEBUG("%sExtended length path attribute bit set for an entry", debug_prepend_string.c_str()); memcpy(&attr_len, data, 2); data += 2; read_size += 2; parse_bgp_lib::SWAP_BYTES(&attr_len); } else attr_len = *data++; read_size++; // Get the attribute data, if we have any; making sure to not overrun buffer if (attr_len > 0 and (read_size + attr_len) <= len) { // Data pointer is currently at the data position of the attribute /* * Parse data based on attribute type */ parseAttrData(attr_type, attr_len, data, update, hash); data += attr_len; read_size += attr_len; SELF_DEBUG("%sParsed attr Type=%d, size=%hu", debug_prepend_string.c_str(), attr_type, attr_len); } else if (attr_len) { LOG_NOTICE("%sAttribute data len of %hu is larger than available data in update message of %hu", debug_prepend_string.c_str(), attr_len, (len - read_size)); return; } } //Now save the generate hash hash.finalize(); // Save the hash unsigned char *hash_raw = hash.raw_digest(); update.attrs[LIB_ATTR_BASE_ATTR_HASH].name = parse_bgp_lib::parse_bgp_lib_attr_names[LIB_ATTR_BASE_ATTR_HASH]; update.attrs[LIB_ATTR_BASE_ATTR_HASH].value.push_back(parse_bgp_lib::hash_toStr(hash_raw)); delete[] hash_raw; }
void Emulator::Load() { Stop(); try { Init(); if (!fs::is_file(m_path)) { LOG_ERROR(LOADER, "File not found: %s", m_path); return; } const std::string& elf_dir = fs::get_parent_dir(m_path); if (IsSelf(m_path)) { const std::size_t elf_ext_pos = m_path.find_last_of('.'); const std::string& elf_ext = fmt::to_upper(m_path.substr(elf_ext_pos != -1 ? elf_ext_pos : m_path.size())); const std::string& elf_name = m_path.substr(elf_dir.size()); if (elf_name.compare(elf_name.find_last_of("/\\", -1, 2) + 1, 9, "EBOOT.BIN", 9) == 0) { m_path.erase(m_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN } else if (elf_ext == ".SELF" || elf_ext == ".SPRX") { m_path.erase(m_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx } else { m_path += ".decrypted.elf"; } if (!DecryptSelf(m_path, elf_dir + elf_name)) { LOG_ERROR(LOADER, "Failed to decrypt %s", elf_dir + elf_name); return; } } ResetInfo(); LOG_NOTICE(LOADER, "Path: %s", m_path); // Load custom config if (fs::file cfg_file{ m_path + ".yml" }) { LOG_NOTICE(LOADER, "Custom config: %s.yml", m_path); cfg::root.from_string(cfg_file.to_string()); } const fs::file elf_file(m_path); ppu_exec_loader ppu_exec; ppu_prx_loader ppu_prx; spu_exec_loader spu_exec; arm_exec_loader arm_exec; if (!elf_file) { LOG_ERROR(LOADER, "Failed to open %s", m_path); return; } else if (ppu_exec.open(elf_file) == elf_error::ok) { // PS3 executable m_status = Ready; vm::ps3::init(); if (m_elf_path.empty()) { m_elf_path = "/host_root/" + m_path; LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); } // Load PARAM.SFO const auto _psf = psf::load_object(fs::file(elf_dir + "/../PARAM.SFO")); m_title = psf::get_string(_psf, "TITLE", m_path); m_title_id = psf::get_string(_psf, "TITLE_ID"); LOG_NOTICE(LOADER, "Title: %s", GetTitle()); LOG_NOTICE(LOADER, "Serial: %s", GetTitleID()); LOG_NOTICE(LOADER, ""); LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string()); // Mount /dev_bdvd/ if (g_cfg_vfs_dev_bdvd.size() == 0 && fs::is_file(elf_dir + "/../../PS3_DISC.SFB")) { const auto dir_list = fmt::split(elf_dir, { "/", "\\" }); // Check latest two directories if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME") { g_cfg_vfs_dev_bdvd = elf_dir.substr(0, elf_dir.length() - 15); } else { g_cfg_vfs_dev_bdvd = elf_dir + "/../../"; } } // Mount /app_home/ if (g_cfg_vfs_app_home.size() == 0) { g_cfg_vfs_app_home = elf_dir + '/'; } vfs::dump(); ppu_exec.load(); Emu.GetCallbackManager().Init(); fxm::import<GSRender>(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall } else if (ppu_prx.open(elf_file) == elf_error::ok) { // PPU PRX (experimental) m_status = Ready; vm::ps3::init(); ppu_prx.load(); GetCallbackManager().Init(); } else if (spu_exec.open(elf_file) == elf_error::ok) { // SPU executable (experimental) m_status = Ready; vm::ps3::init(); spu_exec.load(); } else if (arm_exec.open(elf_file) == elf_error::ok) { // ARMv7 executable m_status = Ready; vm::psv::init(); arm_exec.load(); } else { LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path); LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", ppu_exec.get_error()); LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", ppu_prx.get_error()); LOG_WARNING(LOADER, "** spu_exec_loader -> %s", spu_exec.get_error()); LOG_WARNING(LOADER, "** arm_exec_loader -> %s", arm_exec.get_error()); return; } debug::autopause::reload(); SendDbgCommand(DID_READY_EMU); if (g_cfg_autostart) Run(); } catch (const std::exception& e) { LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what()); Stop(); } }
/** * Parses the BGP prefixes (advertised and withdrawn) in the update * * \details * Parses all attributes. Decoded values are updated in 'parsed_data' * * \param [in] data Pointer to the start of the prefixes to be parsed * \param [in] len Length of the data in bytes to be read * \param [in] nlri_list Reference to parsed_update_data nlri list; */ void parseBgpLib::parseBgpNlri_v4(u_char *data, uint16_t len, std::list<parse_bgp_lib_nlri> &nlri_list) { u_char ipv4_raw[4]; char ipv4_char[16]; u_char addr_bytes; uint32_t path_id; u_char prefix_len; std::ostringstream numString; if (len <= 0 or data == NULL) return; // Loop through all prefixes for (size_t read_size = 0; read_size < len; read_size++) { parse_bgp_lib_nlri nlri; nlri.afi = parse_bgp_lib::BGP_AFI_IPV4; nlri.safi = parse_bgp_lib::BGP_SAFI_UNICAST; nlri.type = parse_bgp_lib::LIB_NLRI_TYPE_NONE; // Generate the hash MD5 hash; bzero(ipv4_raw, sizeof(ipv4_raw)); // Parse add-paths if enabled bool peer_info_addpath = p_info and p_info->add_path_capability.isAddPathEnabled(bgp::BGP_AFI_IPV4, bgp::BGP_SAFI_UNICAST); if ((peer_info_addpath or addPathCap[BGP_AFI_IPV4_INTERNAL][BGP_SAFI_UNICAST_INTERNAL]) and (len - read_size) >= 4) { memcpy(&path_id, data, 4); parse_bgp_lib::SWAP_BYTES(&path_id); data += 4; read_size += 4; } else path_id = 0; numString.str(std::string()); numString << path_id; nlri.nlri[LIB_NLRI_PATH_ID].name = parse_bgp_lib::parse_bgp_lib_nlri_names[LIB_NLRI_PATH_ID]; nlri.nlri[LIB_NLRI_PATH_ID].value.push_back(numString.str()); if (path_id > 0) update_hash(&nlri.nlri[LIB_NLRI_PATH_ID].value, &hash); // set the address in bits length prefix_len = *data++; numString.str(std::string()); numString << static_cast<unsigned>(prefix_len); nlri.nlri[LIB_NLRI_PREFIX_LENGTH].name = parse_bgp_lib::parse_bgp_lib_nlri_names[LIB_NLRI_PREFIX_LENGTH]; nlri.nlri[LIB_NLRI_PREFIX_LENGTH].value.push_back(numString.str()); update_hash(&nlri.nlri[LIB_NLRI_PREFIX_LENGTH].value, &hash); // Figure out how many bytes the bits requires addr_bytes = prefix_len / 8; if (prefix_len % 8) ++addr_bytes; SELF_DEBUG("%sReading NLRI data prefix bits=%d bytes=%d", debug_prepend_string.c_str(), prefix_len, addr_bytes); if (addr_bytes <= 4) { memcpy(ipv4_raw, data, addr_bytes); read_size += addr_bytes; data += addr_bytes; // Convert the IP to string printed format inet_ntop(AF_INET, ipv4_raw, ipv4_char, sizeof(ipv4_char)); nlri.nlri[LIB_NLRI_PREFIX].name = parse_bgp_lib::parse_bgp_lib_nlri_names[LIB_NLRI_PREFIX]; nlri.nlri[LIB_NLRI_PREFIX].value.push_back(ipv4_char); update_hash(&nlri.nlri[LIB_NLRI_PREFIX].value, &hash); SELF_DEBUG("%sAdding prefix %s len %d", debug_prepend_string.c_str(), ipv4_char, prefix_len); // set the raw/binary address nlri.nlri[LIB_NLRI_PREFIX_BIN].name = parse_bgp_lib::parse_bgp_lib_nlri_names[LIB_NLRI_PREFIX_BIN]; nlri.nlri[LIB_NLRI_PREFIX_BIN].value.push_back(std::string(ipv4_raw, ipv4_raw + 4)); //Update hash to include peer hash id if (p_info) hash.update((unsigned char *) p_info->peer_hash_str.c_str(), p_info->peer_hash_str.length()); hash.finalize(); // Save the hash unsigned char *hash_raw = hash.raw_digest(); nlri.nlri[LIB_NLRI_HASH].name = parse_bgp_lib::parse_bgp_lib_nlri_names[LIB_NLRI_HASH]; nlri.nlri[LIB_NLRI_HASH].value.push_back(parse_bgp_lib::hash_toStr(hash_raw)); delete[] hash_raw; nlri.nlri[LIB_NLRI_IS_IPV4].name =parse_bgp_lib_nlri_names[LIB_NLRI_IS_IPV4]; nlri.nlri[LIB_NLRI_IS_IPV4].value.push_back(string("1")); // Add tuple to prefix list nlri_list.push_back(nlri); } else if (addr_bytes > 4) { LOG_NOTICE("%sNRLI v4 address is larger than 4 bytes bytes=%d len=%d", debug_prepend_string.c_str(), addr_bytes, prefix_len); } } }
/** * Parses the BMP router Term message * * \details * Parse BMP Router Init message * \param [in] bmp_data Buffer containing the data * \param [in] parsed_update Reference to parsed_update; will be updated with all parsed data * */ void parseBgpLib::parseBmpTermMsg(int sock, u_char *bmp_data, size_t bmp_data_len, parsed_update &update) { parse_bgp_lib_bmp_msg_v3 termMsg; char infoBuf[BMP_ROUTER_DATA_SIZE]; int infoLen; u_char *bufPtr = bmp_data; /* * Create router timestamp */ update.router[LIB_ROUTER_TIMESTAMP].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_TIMESTAMP]; string ts; getTimestamp(0, 0, ts); update.router[LIB_ROUTER_TIMESTAMP].value.push_back(ts); /* * Loop through the term message (in buffer) to parse each TLV */ for (int i=0; i < bmp_data_len; i += BMP_MSG_LEN) { memcpy(&termMsg, bufPtr, BMP_MSG_LEN); termMsg.info = NULL; bgp::SWAP_BYTES(&termMsg.len); bgp::SWAP_BYTES(&termMsg.type); bufPtr += BMP_MSG_LEN; // Move pointer past the info header LOG_INFO("Term message type %hu and length %hu parsed", termMsg.type, termMsg.len); if (termMsg.len > 0) { infoLen = sizeof(infoBuf) < termMsg.len ? sizeof(infoBuf) : termMsg.len; bzero(infoBuf, sizeof(infoBuf)); memcpy(infoBuf, bufPtr, infoLen); bufPtr += infoLen; // Move pointer past the info data i += infoLen; // Update the counter past the info data termMsg.info = infoBuf; LOG_INFO("Term message type %hu = %s", termMsg.type, termMsg.info); } /* * Save the data based on info type */ switch (termMsg.type) { case TERM_TYPE_FREE_FORM_STRING : update.router[LIB_ROUTER_TERM_DATA].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_TERM_DATA]; update.router[LIB_ROUTER_TERM_DATA].value.push_back(std::string(termMsg.info, infoLen)); break; case TERM_TYPE_REASON : { // Get the term reason code from info data (first 2 bytes) uint16_t term_reason; memcpy(&term_reason, termMsg.info, 2); bgp::SWAP_BYTES(&term_reason); std::ostringstream numString; numString << term_reason; update.router[LIB_ROUTER_TERM_REASON_CODE].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_TERM_REASON_CODE]; update.router[LIB_ROUTER_TERM_REASON_CODE].value.push_back(numString.str()); string term_reason_text; switch (term_reason) { case TERM_REASON_ADMIN_CLOSE : LOG_INFO("BMP session closed by remote administratively"); term_reason_text.assign("Remote session administratively closed"); break; case TERM_REASON_OUT_OF_RESOURCES: LOG_INFO("BMP session closed by remote due to out of resources"); term_reason_text.assign("Remote out of resources"); break; case TERM_REASON_REDUNDANT_CONN: LOG_INFO("BMP session closed by remote due to connection being redundant"); term_reason_text.assign("Remote considers connection redundant"); break; case TERM_REASON_UNSPECIFIED: LOG_INFO("BMP session closed by remote as unspecified"); term_reason_text.assign("Remote closed with unspecified reason"); break; default: LOG_INFO("closed with undefined reason code of %d", term_reason); term_reason_text.assign("Unknown %d termination reason, which is not part of draft.", term_reason); } update.router[LIB_ROUTER_TERM_REASON_TEXT].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_TERM_REASON_TEXT]; update.router[LIB_ROUTER_TERM_REASON_TEXT].value.push_back(term_reason_text); break; } default: LOG_NOTICE("Term message type %hu is unexpected per draft", termMsg.type); } } }
/** * Parses the BMP router init message * * \details * Parse BMP Router Init message * \param [in] bmp_data Buffer containing the data * \param [in] parsed_update Reference to parsed_update; will be updated with all parsed data * */ void parseBgpLib::parseBmpInitMsg(int sock, u_char *bmp_data, size_t bmp_data_len, parsed_update &update) { parse_bgp_lib_bmp_msg_v3 initMsg; char infoBuf[BMP_ROUTER_DATA_SIZE]; int infoLen; u_char *bufPtr = bmp_data; /* * Create router timestamp */ update.router[LIB_ROUTER_TIMESTAMP].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_TIMESTAMP]; string ts; getTimestamp(0, 0, ts); update.router[LIB_ROUTER_TIMESTAMP].value.push_back(ts); /* * Loop through the init message (in buffer) to parse each TLV */ for (int i=0; i < bmp_data_len; i += BMP_MSG_LEN) { memcpy(&initMsg, bufPtr, BMP_MSG_LEN); initMsg.info = NULL; bgp::SWAP_BYTES(&initMsg.len); bgp::SWAP_BYTES(&initMsg.type); bufPtr += BMP_MSG_LEN; // Move pointer past the info header // TODO: Change to SELF_DEBUG after IOS supports INIT messages correctly SELF_DEBUG("Init message type %hu and length %hu parsed", initMsg.type, initMsg.len); if (initMsg.len > 0) { infoLen = sizeof(infoBuf) < initMsg.len ? sizeof(infoBuf) : initMsg.len; bzero(infoBuf, sizeof(infoBuf)); memcpy(infoBuf, bufPtr, infoLen); bufPtr += infoLen; // Move pointer past the info data i += infoLen; // Update the counter past the info data initMsg.info = infoBuf; } /* * Save the data based on info type */ switch (initMsg.type) { case INIT_TYPE_FREE_FORM_STRING : update.router[LIB_ROUTER_INITIATE_DATA].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_INITIATE_DATA]; update.router[LIB_ROUTER_INITIATE_DATA].value.push_back(std::string(initMsg.info, infoLen)); SELF_DEBUG("Init message type %hu = %s", initMsg.type, update.router[LIB_ROUTER_INITIATE_DATA].value.front().c_str()); break; case INIT_TYPE_SYSNAME : update.router[LIB_ROUTER_NAME].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_NAME]; update.router[LIB_ROUTER_NAME].value.push_back(std::string(initMsg.info, infoLen)); SELF_DEBUG("Init message type %hu = %s", initMsg.type, update.router[LIB_ROUTER_NAME].value.front().c_str()); break; case INIT_TYPE_SYSDESCR : update.router[LIB_ROUTER_DESCR].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_DESCR]; update.router[LIB_ROUTER_DESCR].value.push_back(std::string(initMsg.info, infoLen)); SELF_DEBUG("Init message type %hu = %s", initMsg.type, update.router[LIB_ROUTER_DESCR].value.front().c_str()); break; case INIT_TYPE_ROUTER_BGP_ID: if (initMsg.len != sizeof(in_addr_t)) { LOG_NOTICE("Init message type BGP ID not of IPv4 addr length"); break; } char ipv4_char[16]; inet_ntop(AF_INET, initMsg.info, ipv4_char, sizeof(ipv4_char)); update.router[LIB_ROUTER_BGP_ID].name = parse_bgp_lib::parse_bgp_lib_router_names[LIB_ROUTER_BGP_ID]; update.router[LIB_ROUTER_BGP_ID].value.push_back(ipv4_char); SELF_DEBUG("Init message type %hu = %s", initMsg.type, update.router[LIB_ROUTER_BGP_ID].value.front().c_str()); break; default: LOG_NOTICE("Init message type %hu is unexpected per rfc7854", initMsg.type); } } }
void SPUThread::WriteChannel(u32 ch, const u128& r) { const u32 v = r._u32[3]; switch (ch) { case SPU_WrOutIntrMbox: { if (!group) // if RawSPU { if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v); while (!SPU.Out_IntrMBox.Push(v)) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (Emu.IsStopped()) { LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); return; } } m_intrtag[2].stat |= 1; if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread)) { if (t->GetType() == CPU_THREAD_PPU) { if (t->IsAlive()) { LOG_ERROR(Log::SPU, "%s(%s): interrupt thread was alive", __FUNCTION__, spu_ch_name[ch]); Emu.Pause(); return; } PPUThread& ppu = *(PPUThread*)t; ppu.GPR[3] = ppu.m_interrupt_arg; ppu.FastCall2(vm::read32(ppu.entry), vm::read32(ppu.entry + 4)); } } } else { const u8 code = v >> 24; if (code < 64) { /* ===== sys_spu_thread_send_event (used by spu_printf) ===== */ u8 spup = code & 63; u32 data; if (!SPU.Out_MBox.Pop(data)) { LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup); return; } if (Ini.HLELogging.GetValue()) { LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); } EventPort& port = SPUPs[spup]; std::lock_guard<std::mutex> lock(port.m_mutex); if (!port.eq) { LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing return; } if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) { SPU.In_MBox.PushUncond(CELL_EBUSY); return; } SPU.In_MBox.PushUncond(CELL_OK); return; } else if (code < 128) { /* ===== sys_spu_thread_throw_event ===== */ const u8 spup = code & 63; u32 data; if (!SPU.Out_MBox.Pop(data)) { LOG_ERROR(Log::SPU, "sys_spu_thread_throw_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup); return; } //if (Ini.HLELogging.GetValue()) { LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); } EventPort& port = SPUPs[spup]; std::lock_guard<std::mutex> lock(port.m_mutex); if (!port.eq) { LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); return; } // TODO: check passing spup value if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) { LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data); return; } return; } else if (code == 128) { /* ===== sys_event_flag_set_bit ===== */ u32 flag = v & 0xffffff; u32 data; if (!SPU.Out_MBox.Pop(data)) { LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag); return; } if (flag > 63) { LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag); return; } //if (Ini.HLELogging.GetValue()) { LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag); } EventFlag* ef; if (!Emu.GetIdManager().GetIDData(data, ef)) { LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); SPU.In_MBox.PushUncond(CELL_ESRCH); return; } u32 tid = GetCurrentCPUThread()->GetId(); ef->m_mutex.lock(tid); ef->flags |= (u64)1 << flag; if (u32 target = ef->check()) { // if signal, leave both mutexes locked... ef->signal.lock(target); ef->m_mutex.unlock(tid, target); } else { ef->m_mutex.unlock(tid); } SPU.In_MBox.PushUncond(CELL_OK); return; } else if (code == 192) { /* ===== sys_event_flag_set_bit_impatient ===== */ u32 flag = v & 0xffffff; u32 data; if (!SPU.Out_MBox.Pop(data)) { LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(v=0x%x (flag=%d)): Out_MBox is empty", v, flag); return; } if (flag > 63) { LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x): flag > 63", data, v, flag); return; } //if (Ini.HLELogging.GetValue()) { LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag); } EventFlag* ef; if (!Emu.GetIdManager().GetIDData(data, ef)) { LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); return; } u32 tid = GetCurrentCPUThread()->GetId(); ef->m_mutex.lock(tid); ef->flags |= (u64)1 << flag; if (u32 target = ef->check()) { // if signal, leave both mutexes locked... ef->signal.lock(target); ef->m_mutex.unlock(tid, target); } else { ef->m_mutex.unlock(tid); } return; } else { u32 data; if (SPU.Out_MBox.Pop(data)) { LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data); } else { LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x)", v); } SPU.In_MBox.PushUncond(CELL_EINVAL); // ??? return; } } break; } case SPU_WrOutMbox: { while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); break; } case MFC_WrTagMask: { MFC1.QueryMask.SetValue(v); break; } case MFC_WrTagUpdate: { MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue()); break; } case MFC_LSA: { MFC1.LSA.SetValue(v); break; } case MFC_EAH: { MFC1.EAH.SetValue(v); break; } case MFC_EAL: { MFC1.EAL.SetValue(v); break; } case MFC_Size: { MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16)); break; } case MFC_TagID: { MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff)); break; } case MFC_Cmd: { MFC1.CMDStatus.SetValue(v); EnqMfcCmd(MFC1); break; } case MFC_WrListStallAck: { if (v >= 32) { LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: invalid tag(%d)", v); return; } StalledList temp = StallList[v]; if (!temp.MFCArgs) { LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: empty tag(%d)", v); return; } StallList[v].MFCArgs = nullptr; ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs); break; } case SPU_WrDec: { m_dec_start = get_time(); m_dec_value = v; break; } case SPU_WrEventMask: { m_event_mask = v; if (v & ~(SPU_EVENT_IMPLEMENTED)) LOG_ERROR(Log::SPU, "SPU_WrEventMask: unsupported event masked (0x%x)"); break; } case SPU_WrEventAck: { m_events &= ~v; break; } default: { LOG_ERROR(Log::SPU, "%s error (v=0x%x): unknown/illegal channel (%d [%s]).", __FUNCTION__, v, ch, spu_ch_name[ch]); break; } } if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); }
int LsapiConn::processResp() { int ret; while( getState() == PROCESSING ) { if ( m_iPacketHeaderLeft > 0 ) { ret = read( ((char *)&m_respHeader) + sizeof( m_respHeader ) - m_iPacketHeaderLeft, m_iPacketHeaderLeft ); if ( D_ENABLED( DL_MEDIUM ) ) LOG_D(( getLogger(), "[%s] process packet header %d bytes", getLogId(), ret )); if ( ret > 0 ) { m_iPacketHeaderLeft -= ret; if ( m_iPacketHeaderLeft == 0 ) { m_iPacketLeft = verifyPacketHeader( &m_respHeader ) - LSAPI_PACKET_HEADER_LEN; if ( m_iPacketLeft < 0 ) { const char * p = (const char *)&m_respHeader; LOG_WARN(( "[%s] LSAPI Packet header is invalid," "('%c','%c','%c','%c','%c','%c','%c','%c')", getLogId(), *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7) )); break; } // if ( m_iPacketLeft > LSAPI_MAX_HEADER_LEN ) // { // LOG_WARN(( "[%s] LSAPI Packet is too large: %d", // getLogId(), m_iPacketLeft )); // break; // } switch( m_respHeader.m_type ) { case LSAPI_RESP_END: m_respState = 0; incReqProcessed(); setInProcess( 0 ); getConnector()->endResponse( 0, 0 ); return 0; case LSAPI_RESP_HEADER: m_iCurRespHeader = 0; m_respState = LSAPI_CONN_READ_RESP_INFO; m_pRespHeaderProcess = (char *)&m_respInfo; setRespBuf( m_pRespHeaderProcess ); break; case LSAPI_REQ_RECEIVED: m_reqReceived = 1; break; } } } else { if (( m_respState == LSAPI_CONN_READ_RESP_BODY )&& ( getConnector())) getConnector()->flushResp(); return ret; } } if ( m_iPacketLeft > 0 ) { switch( m_respHeader.m_type ) { case LSAPI_RESP_HEADER: ret = processRespHeader(); if ( ret <= 0 ) return ret; break; case LSAPI_RESP_STREAM: ret = readRespBody(); if ( ret <= 0 ) { if (( m_respState == LSAPI_CONN_READ_RESP_BODY )&& ( getConnector())) getConnector()->flushResp(); return ret; } break; case LSAPI_STDERR_STREAM: ret = readStderrStream(); if ( ret <= 0 ) return ret; break; default: //error: protocol error LOG_NOTICE(( getLogger(), "[%s] Unknown Packet Type %c, LSAPI protcol is broken.", getLogId(), m_respHeader.m_type )); errno = EIO; return -1; } } else { m_iPacketHeaderLeft = LSAPI_PACKET_HEADER_LEN; } } errno = EIO; return -1; }
void SPUThread::StopAndSignal(u32 code) { SetExitStatus(code); // exit code (not status) // TODO: process interrupts for RawSPU switch (code) { case 0x110: { /* ===== sys_spu_thread_receive_event ===== */ u32 spuq = 0; if (!SPU.Out_MBox.Pop(spuq)) { LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event: cannot read Out_MBox"); SPU.In_MBox.PushUncond(CELL_EINVAL); // ??? return; } if (SPU.In_MBox.GetCount()) { LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq); SPU.In_MBox.PushUncond(CELL_EBUSY); // ??? return; } if (Ini.HLELogging.GetValue()) { LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq); } EventQueue* eq; if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq)) { SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value return; } u32 tid = GetId(); eq->sq.push(tid); // add thread to sleep queue while (true) { switch (eq->owner.trylock(tid)) { case SMR_OK: if (!eq->events.count()) { eq->owner.unlock(tid); break; } else { u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio(); if (next != tid) { eq->owner.unlock(tid, next); break; } } case SMR_SIGNAL: { sys_event_data event; eq->events.pop(event); eq->owner.unlock(tid); SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond((u32)event.data1); SPU.In_MBox.PushUncond((u32)event.data2); SPU.In_MBox.PushUncond((u32)event.data3); return; } case SMR_FAILED: break; default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (Emu.IsStopped()) { LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); eq->sq.invalidate(tid); return; } } break; } case 0x101: { /* ===== sys_spu_thread_group_exit ===== */ if (!group) { LOG_ERROR(Log::SPU, "sys_spu_thread_group_exit(): group not set"); break; } else if (!SPU.Out_MBox.GetCount()) { LOG_ERROR(Log::SPU, "sys_spu_thread_group_exit(): Out_MBox is empty"); } else if (Ini.HLELogging.GetValue()) { LOG_NOTICE(Log::SPU, "sys_spu_thread_group_exit(status=0x%x)", SPU.Out_MBox.GetValue()); } group->m_group_exit = true; group->m_exit_status = SPU.Out_MBox.GetValue(); for (auto& v : group->list) { if (CPUThread* t = Emu.GetCPU().GetThread(v)) { t->Stop(); } } break; } case 0x102: { /* ===== sys_spu_thread_exit ===== */ if (!SPU.Out_MBox.GetCount()) { LOG_ERROR(Log::SPU, "sys_spu_thread_exit(): Out_MBox is empty"); } else if (Ini.HLELogging.GetValue()) { // the real exit status LOG_NOTICE(Log::SPU, "sys_spu_thread_exit(status=0x%x)", SPU.Out_MBox.GetValue()); } SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP); Stop(); break; } default: { if (!SPU.Out_MBox.GetCount()) { LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (no message)", code); } else { LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue()); } Stop(); break; } } }
int LsapiConn::readStderrStream() { register HttpExtConnector * pHEC = getConnector(); int ret; size_t bufLen; char achBuf[2049]; while( m_iPacketLeft > 0 ) { char * pBuf = achBuf; bufLen = sizeof( achBuf ); int toRead = m_iPacketLeft + sizeof( m_respHeader ); if ( toRead > (int)bufLen ) toRead = bufLen ; ret = read( pBuf, toRead ); if ( ret > 0 ) { int len, packetLen; if ( D_ENABLED( DL_MEDIUM ) ) LOG_D(( getLogger(), "[%s] process STDERR stream %d bytes, packet left: %d", getLogId(), ret, m_iPacketLeft )); if ( ret >= m_iPacketLeft ) { packetLen = m_iPacketLeft; m_iPacketLeft = 0; } else { packetLen = ret; m_iPacketLeft -= ret; } if (( packetLen == 8 )&& !m_iPacketLeft && ( m_respHeader.m_packetLen.m_iLen == 16 ) && ( memcmp( achBuf, "\0PID", 4 ) == 0 ) ) { //ignore this packet for now. } else if ( pHEC ) pHEC->processErrData( pBuf, packetLen ); else { char ch = pBuf[packetLen]; pBuf[ packetLen ] = 0; LOG_NOTICE(( getLogger(), "[%s] [LSAPI:STDERR]: %s", getLogId(), pBuf )); pBuf[ packetLen ] = ch; } if ( m_iPacketLeft <= 0 ) { m_iPacketHeaderLeft = LSAPI_PACKET_HEADER_LEN; if ( ret > packetLen ) { if ( D_ENABLED( DL_MEDIUM ) ) LOG_D(( getLogger(), "[%s] process packet header %d bytes", getLogId(), ret - packetLen )); len = processPacketHeader( pBuf + packetLen, ret - packetLen ); if ( len <= 0 ) return len; if (( m_respHeader.m_type != LSAPI_STDERR_STREAM )|| ( m_iPacketLeft <= 0 )) return 1; } else break; } } else { return ret; } } return 1; }
u32 vdecOpen(VideoDecoder* data) { VideoDecoder& vdec = *data; vdec.vdecCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); u32 vdec_id = cellVdec->GetNewId(data); vdec.id = vdec_id; vdec.vdecCb->SetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback"); thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]() { LOG_NOTICE(HLE, "Video Decoder thread started"); VdecTask& task = vdec.task; while (true) { if (Emu.IsStopped()) { break; } if (vdec.job.IsEmpty() && vdec.is_running) { Sleep(1); continue; } if (vdec.frames.GetCount() >= 50) { Sleep(1); continue; } if (!vdec.job.Pop(task)) { break; } switch (task.type) { case vdecStartSeq: { // TODO: reset data LOG_WARNING(HLE, "vdecStartSeq:"); vdec.reader.addr = 0; vdec.reader.size = 0; vdec.is_running = true; vdec.just_started = true; } break; case vdecEndSeq: { // TODO: finalize LOG_WARNING(HLE, "vdecEndSeq:"); vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); /*Callback cb; cb.SetAddr(vdec.cbFunc); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); cb.Branch(true); // ???*/ avcodec_close(vdec.ctx); avformat_close_input(&vdec.fmt); vdec.is_running = false; } break; case vdecDecodeAu: { int err; if (task.mode != CELL_VDEC_DEC_MODE_NORMAL) { LOG_ERROR(HLE, "vdecDecodeAu: unsupported decoding mode(%d)", task.mode); break; } vdec.reader.addr = task.addr; vdec.reader.size = task.size; //LOG_NOTICE(HLE, "Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts); if (vdec.just_started) { vdec.first_pts = task.pts; vdec.last_pts = task.pts; vdec.first_dts = task.dts; } struct AVPacketHolder : AVPacket { AVPacketHolder(u32 size) { av_init_packet(this); if (size) { data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); this->size = size + FF_INPUT_BUFFER_PADDING_SIZE; } else { data = NULL; size = 0; } } ~AVPacketHolder() { av_free(data); //av_free_packet(this); } } au(0); if (vdec.just_started) // deferred initialization { err = avformat_open_input(&vdec.fmt, NULL, av_find_input_format("mpeg"), NULL); if (err) { LOG_ERROR(HLE, "vdecDecodeAu: avformat_open_input() failed"); Emu.Pause(); break; } AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); // ??? if (!codec) { LOG_ERROR(HLE, "vdecDecodeAu: avcodec_find_decoder() failed"); Emu.Pause(); break; } /*err = avformat_find_stream_info(vdec.fmt, NULL); if (err) { LOG_ERROR(HLE, "vdecDecodeAu: avformat_find_stream_info() failed"); Emu.Pause(); break; } if (!vdec.fmt->nb_streams) { LOG_ERROR(HLE, "vdecDecodeAu: no stream found"); Emu.Pause(); break; }*/ if (!avformat_new_stream(vdec.fmt, codec)) { LOG_ERROR(HLE, "vdecDecodeAu: avformat_new_stream() failed"); Emu.Pause(); break; } vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data AVDictionary* opts = nullptr; av_dict_set(&opts, "refcounted_frames", "1", 0); { std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2); // not multithread-safe err = avcodec_open2(vdec.ctx, codec, &opts); } if (err) { LOG_ERROR(HLE, "vdecDecodeAu: avcodec_open2() failed"); Emu.Pause(); break; } //vdec.ctx->flags |= CODEC_FLAG_TRUNCATED; //vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS; vdec.just_started = false; } bool last_frame = false; while (true) { if (Emu.IsStopped()) { LOG_WARNING(HLE, "vdecDecodeAu: aborted"); return; } last_frame = av_read_frame(vdec.fmt, &au) < 0; if (last_frame) { //break; av_free(au.data); au.data = NULL; au.size = 0; } struct VdecFrameHolder : VdecFrame { VdecFrameHolder() { data = av_frame_alloc(); } ~VdecFrameHolder() { if (data) { av_frame_unref(data); av_frame_free(&data); } } } frame; if (!frame.data) { LOG_ERROR(HLE, "vdecDecodeAu: av_frame_alloc() failed"); Emu.Pause(); break; } int got_picture = 0; int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &au); if (decode <= 0) { if (!last_frame && decode < 0) { LOG_ERROR(HLE, "vdecDecodeAu: AU decoding error(0x%x)", decode); } if (!got_picture && vdec.reader.size == 0) break; // video end? } if (got_picture) { u64 ts = av_frame_get_best_effort_timestamp(frame.data); if (ts != AV_NOPTS_VALUE) { frame.pts = ts/* - vdec.first_pts*/; // ??? vdec.last_pts = frame.pts; } else { vdec.last_pts += vdec.ctx->time_base.num * 90000 / (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame); frame.pts = vdec.last_pts; } //frame.pts = vdec.last_pts; //vdec.last_pts += 3754; frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.userdata = task.userData; //LOG_NOTICE(HLE, "got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); vdec.frames.Push(frame); // !!!!!!!! frame.data = nullptr; // to prevent destruction vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); /*Callback cb; cb.SetAddr(vdec.cbFunc); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); cb.Branch(false);*/ } } vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); /*Callback cb; cb.SetAddr(vdec.cbFunc); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); cb.Branch(false);*/ } break; case vdecClose: { vdec.is_finished = true; LOG_NOTICE(HLE, "Video Decoder thread ended"); return; } case vdecSetFrameRate: { LOG_ERROR(HLE, "TODO: vdecSetFrameRate(%d)", task.frc); } break; default: LOG_ERROR(HLE, "Video Decoder thread error: unknown task(%d)", task.type); } } vdec.is_finished = true; LOG_WARNING(HLE, "Video Decoder thread aborted"); }); t.detach(); return vdec_id; }
void GLGSRender::flip(int buffer) { u32 buffer_width = gcm_buffers[buffer].width; u32 buffer_height = gcm_buffers[buffer].height; u32 buffer_pitch = gcm_buffers[buffer].pitch; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDisable(GL_SCISSOR_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); rsx::tiled_region buffer_region = get_tiled_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL); u32 absolute_address = buffer_region.address + buffer_region.base; if (0) { LOG_NOTICE(RSX, "flip(%d) -> 0x%x [0x%x]", buffer, absolute_address, rsx::get_address(gcm_buffers[1 - buffer].offset, CELL_GCM_LOCATION_LOCAL)); } gl::texture *render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address); /** * Calling read_buffers will overwrite cached content */ __glcheck m_flip_fbo.recreate(); m_flip_fbo.bind(); auto *flip_fbo = &m_flip_fbo; if (render_target_texture) { __glcheck m_flip_fbo.color = *render_target_texture; __glcheck m_flip_fbo.read_buffer(m_flip_fbo.color); } else if (draw_fbo) { //HACK! it's here, because textures cache isn't implemented correctly! flip_fbo = &draw_fbo; } else { if (!m_flip_tex_color || m_flip_tex_color.size() != sizei{ (int)buffer_width, (int)buffer_height }) { m_flip_tex_color.recreate(gl::texture::target::texture2D); __glcheck m_flip_tex_color.config() .size({ (int)buffer_width, (int)buffer_height }) .type(gl::texture::type::uint_8_8_8_8) .format(gl::texture::format::bgra); m_flip_tex_color.pixel_unpack_settings().aligment(1).row_length(buffer_pitch / 4); } if (buffer_region.tile) { std::unique_ptr<u8[]> temp(new u8[buffer_height * buffer_pitch]); buffer_region.read(temp.get(), buffer_width, buffer_height, buffer_pitch); __glcheck m_flip_tex_color.copy_from(temp.get(), gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8); } else { __glcheck m_flip_tex_color.copy_from(buffer_region.ptr, gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8); } m_flip_fbo.color = m_flip_tex_color; __glcheck m_flip_fbo.read_buffer(m_flip_fbo.color); } areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height }); coordi aspect_ratio; if (1) //enable aspect ratio { sizei csize(m_frame->client_width(), m_frame->client_height()); sizei new_size = csize; const double aq = (double)buffer_width / buffer_height; const double rq = (double)new_size.width / new_size.height; const double q = aq / rq; if (q > 1.0) { new_size.height = int(new_size.height / q); aspect_ratio.y = (csize.height - new_size.height) / 2; } else if (q < 1.0) { new_size.width = int(new_size.width * q); aspect_ratio.x = (csize.width - new_size.width) / 2; } aspect_ratio.size = new_size; } else { aspect_ratio.size = { m_frame->client_width(), m_frame->client_height() }; } gl::screen.clear(gl::buffers::color_depth_stencil); __glcheck flip_fbo->blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical()); if (g_cfg_rsx_overlay) { gl::screen.bind(); glViewport(0, 0, m_frame->client_width(), m_frame->client_height()); m_text_printer.print_text(0, 0, m_frame->client_width(), m_frame->client_height(), "draw calls: " + std::to_string(m_draw_calls)); m_text_printer.print_text(0, 18, m_frame->client_width(), m_frame->client_height(), "draw call setup: " + std::to_string(m_begin_time) + "us"); m_text_printer.print_text(0, 36, m_frame->client_width(), m_frame->client_height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); m_text_printer.print_text(0, 54, m_frame->client_width(), m_frame->client_height(), "textures upload time: " + std::to_string(m_textures_upload_time) + "us"); m_text_printer.print_text(0, 72, m_frame->client_width(), m_frame->client_height(), "draw call execution: " + std::to_string(m_draw_time) + "us"); } m_frame->flip(m_context); m_draw_calls = 0; m_begin_time = 0; m_draw_time = 0; m_vertex_upload_time = 0; m_textures_upload_time = 0; for (auto &tex : m_rtts.invalidated_resources) { tex->remove(); } m_rtts.invalidated_resources.clear(); }
void PE_Open() { LOG_NOTICE(TPE, "initialized ok"); memset(PERegisters, 0, sizeof(PERegisters)); }
void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load) { int count = 0; if (is_load) { count = rpcs3::config.vfs.count.value(); if (!count) { res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd0/", "/dev_hdd0/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd1/", "/dev_hdd1/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/"); res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/"); res.emplace_back(vfsDevice_LocalFile, "", "/host_root/"); return; } res.resize(count); } else { count = (int)res.size(); rpcs3::config.vfs.count = count; } // Custom EmulationDir if (rpcs3::config.system.emulation_dir_path_enable.value()) { std::string dir = rpcs3::config.system.emulation_dir_path.value(); if (dir.empty()) { rpcs3::config.system.emulation_dir_path = Emu.GetEmulatorPath(); } if (!fs::is_dir(dir)) { LOG_ERROR(GENERAL, "Custom EmulationDir: directory '%s' not found", dir); } else { LOG_NOTICE(GENERAL, "Custom EmulationDir: $(EmulatorDir) bound to '%s'", dir); } } for(int i=0; i<count; ++i) { rpcs3::config.vfs.add_entry(fmt::format("path[%d]", i), std::string{}); rpcs3::config.vfs.add_entry(fmt::format("device_path[%d]", i), std::string{}); rpcs3::config.vfs.add_entry(fmt::format("mount[%d]", i), std::string{}); rpcs3::config.vfs.add_entry(fmt::format("device[%d]", i), 0); if (is_load) { res[i] = VFSManagerEntry(); res[i].path = rpcs3::config.vfs.get_entry_value<std::string>(fmt::format("path[%d]", i), std::string{}); res[i].device_path = rpcs3::config.vfs.get_entry_value<std::string>(fmt::format("device_path[%d]", i), std::string{}); res[i].mount = rpcs3::config.vfs.get_entry_value<std::string>(fmt::format("mount[%d]", i), std::string{}); res[i].device = (vfsDeviceType)rpcs3::config.vfs.get_entry_value<int>(fmt::format("device[%d]", i), 0); } else { rpcs3::config.vfs.set_entry_value(fmt::format("path[%d]", i), res[i].path); rpcs3::config.vfs.set_entry_value(fmt::format("device_path[%d]", i), res[i].device_path); rpcs3::config.vfs.set_entry_value(fmt::format("mount[%d]", i), res[i].mount); rpcs3::config.vfs.set_entry_value(fmt::format("device[%d]", i), (int)res[i].device); } } }
void SELFDecrypter::ShowHeaders(bool isElf32) { LOG_NOTICE(LOADER, "SCE header"); LOG_NOTICE(LOADER, "----------------------------------------------------"); sce_hdr.Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "SELF header"); LOG_NOTICE(LOADER, "----------------------------------------------------"); self_hdr.Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "APP INFO"); LOG_NOTICE(LOADER, "----------------------------------------------------"); app_info.Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "ELF header"); LOG_NOTICE(LOADER, "----------------------------------------------------"); isElf32 ? elf32_hdr.Show() : elf64_hdr.Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "ELF program headers"); LOG_NOTICE(LOADER, "----------------------------------------------------"); for(unsigned int i = 0; i < ((isElf32) ? phdr32_arr.size() : phdr64_arr.size()); i++) isElf32 ? phdr32_arr[i].Show() : phdr64_arr[i].Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "Section info"); LOG_NOTICE(LOADER, "----------------------------------------------------"); for(unsigned int i = 0; i < secinfo_arr.size(); i++) secinfo_arr[i].Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "SCE version info"); LOG_NOTICE(LOADER, "----------------------------------------------------"); scev_info.Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "Control info"); LOG_NOTICE(LOADER, "----------------------------------------------------"); for(unsigned int i = 0; i < ctrlinfo_arr.size(); i++) ctrlinfo_arr[i].Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); LOG_NOTICE(LOADER, "ELF section headers"); LOG_NOTICE(LOADER, "----------------------------------------------------"); for(unsigned int i = 0; i < ((isElf32) ? shdr32_arr.size() : shdr64_arr.size()); i++) isElf32 ? shdr32_arr[i].Show() : shdr64_arr[i].Show(); LOG_NOTICE(LOADER, "----------------------------------------------------"); }
bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size) { aes_context aes; ControlInfo *ctrl = NULL; u8 npdrm_key[0x10]; u8 npdrm_iv[0x10]; // Parse the control info structures to find the NPDRM control info. for(unsigned int i = 0; i < ctrlinfo_arr.size(); i++) { if (ctrlinfo_arr[i].type == 3) { ctrl = &ctrlinfo_arr[i]; break; } } // Check if we have a valid NPDRM control info structure. // If not, the data has no NPDRM layer. if (!ctrl) { LOG_NOTICE(LOADER, "SELF: No NPDRM control info found!"); return true; } if (ctrl->npdrm.license == 1) // Network license. { LOG_ERROR(LOADER, "SELF: Can't decrypt network NPDRM!"); return false; } else if (ctrl->npdrm.license == 2) // Local license. { // Try to find a RAP file to get the key. if (!GetKeyFromRap(ctrl->npdrm.content_id, npdrm_key)) { LOG_ERROR(LOADER, "SELF: Can't find RAP file for NPDRM decryption!"); return false; } } else if (ctrl->npdrm.license == 3) // Free license. { // Use klicensee if available. if (key_v.GetKlicenseeKey() != nullptr) memcpy(npdrm_key, key_v.GetKlicenseeKey(), 0x10); else memcpy(npdrm_key, NP_KLIC_FREE, 0x10); } else { LOG_ERROR(LOADER, "SELF: Invalid NPDRM license type!"); return false; } // Decrypt our key with NP_KLIC_KEY. aes_setkey_dec(&aes, NP_KLIC_KEY, 128); aes_crypt_ecb(&aes, AES_DECRYPT, npdrm_key, npdrm_key); // IV is empty. memset(npdrm_iv, 0, 0x10); // Use our final key to decrypt the NPDRM layer. aes_setkey_dec(&aes, npdrm_key, 128); aes_crypt_cbc(&aes, AES_DECRYPT, metadata_size, npdrm_iv, metadata, metadata); return true; }
void CPUThread::Task() { if (Ini.HLELogging.GetValue()) LOG_NOTICE(GENERAL, "%s enter", CPUThread::GetFName().c_str()); const std::vector<u64>& bp = Emu.GetBreakPoints(); for (uint i = 0; i<bp.size(); ++i) { if (bp[i] == m_offset + PC) { Emu.Pause(); break; } } std::vector<u32> trace; #ifdef _WIN32 auto old_se_translator = _set_se_translator(_se_translator); #else // TODO: linux version #endif try { while (true) { int status = ThreadStatus(); if (status == CPUThread_Stopped || status == CPUThread_Break) { break; } if (status == CPUThread_Sleeping) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } Step(); //if (m_trace_enabled) trace.push_back(PC); NextPc(m_dec->DecodeMemory(PC + m_offset)); if (status == CPUThread_Step) { m_is_step = false; break; } for (uint i = 0; i < bp.size(); ++i) { if (bp[i] == PC) { Emu.Pause(); break; } } } } catch (const std::string& e) { LOG_ERROR(GENERAL, "Exception: %s", e.c_str()); Emu.Pause(); } catch (const char* e) { LOG_ERROR(GENERAL, "Exception: %s", e); Emu.Pause(); } #ifdef _WIN32 _set_se_translator(old_se_translator); #else // TODO: linux version #endif if (trace.size()) { LOG_NOTICE(GENERAL, "Trace begin (%d elements)", trace.size()); u32 start = trace[0], prev = trace[0] - 4; for (auto& v : trace) //LOG_NOTICE(GENERAL, "PC = 0x%x", v); { if (v - prev != 4) { LOG_NOTICE(GENERAL, "Trace: 0x%08x .. 0x%08x", start, prev); start = v; } prev = v; } LOG_NOTICE(GENERAL, "Trace end: 0x%08x .. 0x%08x", start, prev); } if (Ini.HLELogging.GetValue()) LOG_NOTICE(GENERAL, "%s leave", CPUThread::GetFName().c_str()); }
void GLGSRender::on_init_thread() { GSRender::on_init_thread(); gl::init(); //Enable adaptive vsync if vsync is requested gl::set_swapinterval(g_cfg.video.vsync ? -1 : 0); if (g_cfg.video.debug_output) gl::enable_debugging(); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VERSION)); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VENDOR)); auto& gl_caps = gl::get_driver_caps(); if (!gl_caps.ARB_texture_buffer_supported) { fmt::throw_exception("Failed to initialize OpenGL renderer. ARB_texture_buffer_object is required but not supported by your GPU"); } if (!gl_caps.ARB_dsa_supported && !gl_caps.EXT_dsa_supported) { fmt::throw_exception("Failed to initialize OpenGL renderer. ARB_direct_state_access or EXT_direct_state_access is required but not supported by your GPU"); } if (!gl_caps.ARB_depth_buffer_float_supported && g_cfg.video.force_high_precision_z_buffer) { LOG_WARNING(RSX, "High precision Z buffer requested but your GPU does not support GL_ARB_depth_buffer_float. Option ignored."); } if (!gl_caps.ARB_texture_barrier_supported && !gl_caps.NV_texture_barrier_supported && !g_cfg.video.strict_rendering_mode) { LOG_WARNING(RSX, "Texture barriers are not supported by your GPU. Feedback loops will have undefined results."); } //Use industry standard resource alignment values as defaults m_uniform_buffer_offset_align = 256; m_min_texbuffer_alignment = 256; glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_uniform_buffer_offset_align); glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &m_min_texbuffer_alignment); m_vao.create(); //Set min alignment to 16-bytes for SSE optimizations with aligned addresses to work m_min_texbuffer_alignment = std::max(m_min_texbuffer_alignment, 16); m_uniform_buffer_offset_align = std::max(m_uniform_buffer_offset_align, 16); const u32 texture_index_offset = rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count; //Array stream buffer { auto &tex = m_gl_persistent_stream_buffer; tex.create(); tex.set_target(gl::texture::target::textureBuffer); glActiveTexture(GL_TEXTURE0 + texture_index_offset); tex.bind(); } //Register stream buffer { auto &tex = m_gl_volatile_stream_buffer; tex.create(); tex.set_target(gl::texture::target::textureBuffer); glActiveTexture(GL_TEXTURE0 + texture_index_offset + 1); tex.bind(); } if (!gl_caps.ARB_buffer_storage_supported) { LOG_WARNING(RSX, "Forcing use of legacy OpenGL buffers because ARB_buffer_storage is not supported"); // TODO: do not modify config options g_cfg.video.gl_legacy_buffers.from_string("true"); } if (g_cfg.video.gl_legacy_buffers) { LOG_WARNING(RSX, "Using legacy openGL buffers."); manually_flush_ring_buffers = true; m_attrib_ring_buffer.reset(new gl::legacy_ring_buffer()); m_transform_constants_buffer.reset(new gl::legacy_ring_buffer()); m_fragment_constants_buffer.reset(new gl::legacy_ring_buffer()); m_vertex_state_buffer.reset(new gl::legacy_ring_buffer()); m_index_ring_buffer.reset(new gl::legacy_ring_buffer()); } else { m_attrib_ring_buffer.reset(new gl::ring_buffer()); m_transform_constants_buffer.reset(new gl::ring_buffer()); m_fragment_constants_buffer.reset(new gl::ring_buffer()); m_vertex_state_buffer.reset(new gl::ring_buffer()); m_index_ring_buffer.reset(new gl::ring_buffer()); } m_attrib_ring_buffer->create(gl::buffer::target::texture, 256 * 0x100000); m_index_ring_buffer->create(gl::buffer::target::element_array, 64 * 0x100000); m_transform_constants_buffer->create(gl::buffer::target::uniform, 16 * 0x100000); m_fragment_constants_buffer->create(gl::buffer::target::uniform, 16 * 0x100000); m_vertex_state_buffer->create(gl::buffer::target::uniform, 16 * 0x100000); m_vao.element_array_buffer = *m_index_ring_buffer; if (g_cfg.video.overlay) { if (gl_caps.ARB_shader_draw_parameters_supported) { m_text_printer.init(); m_text_printer.set_enabled(true); } } for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) { m_gl_sampler_states[i].create(); m_gl_sampler_states[i].bind(i); } //Occlusion query for (u32 i = 0; i < occlusion_query_count; ++i) { auto &query = occlusion_query_data[i]; glGenQueries(1, &query.handle); query.pending = false; query.active = false; query.result = 0; } //Clip planes are shader controlled; enable all planes driver-side glEnable(GL_CLIP_DISTANCE0 + 0); glEnable(GL_CLIP_DISTANCE0 + 1); glEnable(GL_CLIP_DISTANCE0 + 2); glEnable(GL_CLIP_DISTANCE0 + 3); glEnable(GL_CLIP_DISTANCE0 + 4); glEnable(GL_CLIP_DISTANCE0 + 5); m_gl_texture_cache.initialize(this); m_shaders_cache->load(); }
void Selector::threadMain() { TRACE_BEGIN( LOG_LVL_INFO ); bool gotEvent = false; struct pollfd fds[ kMaxPollFds ]; int numFds = 0; fillPollFds( fds, numFds ); // Event will be sent by EventThread on exit while( mRunning ) { LOG( "%p on %d files", this, numFds ); for ( int i = 1; i < numFds; i++ ) { LOG( "%p fd %d", this, fds[ i ].fd ); } // set errno to zero // this is being set to better monitor the behavior of poll on // the 7401 until poll gets fixed errno = 0; int res = 0; // test here to ensure that errno cannot be modified before it is tested. if ( ( res = poll( fds, numFds, -1 ) ) < 0 ) { // for whatever reason, there are times when poll returns -1, // but doesn't set errno if (errno == 0) LOG_NOTICE( "Poll returned %d, but didn't set errno", res); else if (errno == EINTR) LOG_NOISE( "Poll was interrupted" ); else LOG_ERR_PERROR( "Poll returned %d", res ); } LOG( "%p woke up %d", this, res ); if ( res > 0 ) { LOG( "got %d from poll", res ); for ( int i = 0; i < numFds; i++ ) { if ( fds[ i ].fd == mPipe[ PIPE_READER ] ) { LOG( "got %x on pipe %d", fds[ 0 ].revents, fds[ i ].fd ); if ( fds[ i ].revents & POLLIN ) { char buf[10]; read( mPipe[ PIPE_READER ], &buf, 4 ); // We need to handle events after we handle file // descriptor polls because one of the events // that we handle modifies the current list of // file descriptors for poll and we need to handle // any that occured before updating them. gotEvent = true; } else if ( fds[ i ].revents & ( POLLHUP | POLLNVAL ) ) { LOG_ERR_FATAL( "POLLHUP recieved on pipe" ); } } else { LOG_NOISE( "got %x on fd %d", fds[ i ].revents, fds[ i ].fd ); if ( fds[ i ].revents != 0 ) { // if callListeners removes a listener we need to update // Fds. However only set if callListeners returns true // This should not be cleared since one of the listeners // could have called removeListener and that call might // have set mUpdateFds if ( callListeners( fds[ i ].fd, fds[ i ].revents ) ) mUpdateFds = true; } } } } // Now that file descriptors have been handled we can deal with // events if needed, including updating the poll file descriptor // list if it's been changed. if ( gotEvent ) { Event *ev = mQueue.PollEvent(); if ( ev == NULL ) { LOG_WARN( "got NULL event" ); } else if ( ev->getEventId() == Event::kSelectorUpdateEventId ) { LOG( "got kSelectorUpdateEventId" ); mUpdateFds = true; ev->Release(); } else { LOG( "got event %d", ev->getEventId() ); bool done = EventDispatcher::handleEvent( ev ); if ( done ) mRunning = false; } gotEvent = false; } if ( mUpdateFds ) { fillPollFds( fds, numFds ); mUpdateFds = false; } mCondition.Broadcast(); } LOG_NOTICE( "Thread exiting" ); }
void SPUThread::EnqMfcCmd(MFCReg& MFCArgs) { u32 cmd = MFCArgs.CMDStatus.GetValue(); u16 op = cmd & MFC_MASK_CMD; u32 lsa = MFCArgs.LSA.GetValue(); u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32); u32 size_tag = MFCArgs.Size_Tag.GetValue(); u16 tag = (u16)size_tag; u16 size = size_tag >> 16; switch (op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK)) { case MFC_PUT_CMD: case MFC_PUTR_CMD: // ??? case MFC_GET_CMD: { if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x", (op & MFC_PUT_CMD ? "PUT" : "GET"), (op & MFC_RESULT_MASK ? "R" : ""), (op & MFC_BARRIER_MASK ? "B" : ""), (op & MFC_FENCE_MASK ? "F" : ""), lsa, ea, tag, size, cmd); ProcessCmd(cmd, tag, lsa, ea, size); MFCArgs.CMDStatus.SetValue(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL); break; } case MFC_PUTL_CMD: case MFC_PUTRL_CMD: // ??? case MFC_GETL_CMD: { if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x", (op & MFC_PUT_CMD ? "PUT" : "GET"), (op & MFC_RESULT_MASK ? "RL" : "L"), (op & MFC_BARRIER_MASK ? "B" : ""), (op & MFC_FENCE_MASK ? "F" : ""), lsa, ea, tag, size, cmd); ListCmd(lsa, ea, tag, size, cmd, MFCArgs); break; } case MFC_GETLLAR_CMD: case MFC_PUTLLC_CMD: case MFC_PUTLLUC_CMD: case MFC_PUTQLLUC_CMD: { if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x", (op == MFC_GETLLAR_CMD ? "GETLLAR" : op == MFC_PUTLLC_CMD ? "PUTLLC" : op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"), lsa, ea, tag, size, cmd); if (op == MFC_GETLLAR_CMD) // get reservation { if (R_ADDR) { m_events |= SPU_EVENT_LR; } R_ADDR = ea; for (u32 i = 0; i < 16; i++) { R_DATA[i] = vm::get_ptr<u64>(R_ADDR)[i]; vm::get_ptr<u64>(dmac.ls_offset + lsa)[i] = R_DATA[i]; } MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS); } else if (op == MFC_PUTLLC_CMD) // store conditional { MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); if (R_ADDR == ea) { u32 changed = 0, mask = 0; u64 buf[16]; for (u32 i = 0; i < 16; i++) { buf[i] = vm::get_ptr<u64>(dmac.ls_offset + lsa)[i]; if (buf[i] != R_DATA[i]) { changed++; mask |= (0x3 << (i * 2)); if (vm::get_ptr<u64>(R_ADDR)[i] != R_DATA[i]) { m_events |= SPU_EVENT_LR; MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); R_ADDR = 0; return; } } } for (u32 i = 0; i < 16; i++) { if (buf[i] != R_DATA[i]) { if (InterlockedCompareExchange(&vm::get_ptr<volatile u64>(ea)[i], buf[i], R_DATA[i]) != R_DATA[i]) { m_events |= SPU_EVENT_LR; MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); if (changed > 1) { LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Memory corrupted (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", changed, mask, op, cmd, lsa, ea, tag, size); Emu.Pause(); } break; } } } if (changed > 1) { LOG_WARNING(Log::SPU, "MFC_PUTLLC_CMD: Reservation impossibru (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", changed, mask, op, cmd, lsa, ea, tag, size); SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode); for (s32 i = (s32)PC; i < (s32)PC + 4 * 7; i += 4) { dis_asm.dump_pc = i; dis_asm.offset = vm::get_ptr<u8>(dmac.ls_offset); const u32 opcode = vm::read32(i + dmac.ls_offset); (*SPU_instr::rrr_list)(&dis_asm, opcode); if (i >= 0 && i < 0x40000) { LOG_NOTICE(Log::SPU, "*** %s", dis_asm.last_opcode.c_str()); } } } } else { MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); } R_ADDR = 0; } else // store unconditional { if (R_ADDR) { m_events |= SPU_EVENT_LR; } ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); if (op == MFC_PUTLLUC_CMD) { MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS); } R_ADDR = 0; } break; } default: LOG_ERROR(Log::SPU, "Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", op, cmd, lsa, ea, tag, size); break; } }
void Emulator::Stop() { if (m_state.exchange(system_state::stopped) == system_state::stopped) { return; } LOG_NOTICE(GENERAL, "Stopping emulator..."); GetCallbacks().on_stop(); #ifdef WITH_GDB_DEBUGGER //fxm for some reason doesn't call on_stop fxm::get<GDBDebugServer>()->on_stop(); fxm::remove<GDBDebugServer>(); #endif auto e_stop = std::make_exception_ptr(cpu_flag::dbg_global_stop); auto on_select = [&](u32, cpu_thread& cpu) { cpu.state += cpu_flag::dbg_global_stop; cpu.get()->set_exception(e_stop); }; idm::select<ppu_thread>(on_select); idm::select<ARMv7Thread>(on_select); idm::select<RawSPUThread>(on_select); idm::select<SPUThread>(on_select); if (auto mfc = fxm::check<mfc_thread>()) { on_select(0, *mfc); } LOG_NOTICE(GENERAL, "All threads signaled..."); while (g_thread_count) { m_cb.process_events(); std::this_thread::sleep_for(10ms); } LOG_NOTICE(GENERAL, "All threads stopped..."); lv2_obj::cleanup(); idm::clear(); fxm::clear(); LOG_NOTICE(GENERAL, "Objects cleared..."); RSXIOMem.Clear(); vm::close(); if (g_cfg.misc.autoexit) { GetCallbacks().exit(); } else { Init(); } #ifdef LLVM_AVAILABLE extern void jit_finalize(); jit_finalize(); #endif }
void thread::on_task() { on_init_thread(); reset(); last_flip_time = get_system_time() - 1000000; scope_thread_t vblank(PURE_EXPR("VBlank Thread"s), [this]() { const u64 start_time = get_system_time(); vblank_count = 0; // TODO: exit condition while (!Emu.IsStopped()) { if (get_system_time() - start_time > vblank_count * 1000000 / 60) { vblank_count++; if (vblank_handler) { Emu.GetCallbackManager().Async([func = vblank_handler](PPUThread& ppu) { func(ppu, 1); }); } continue; } std::this_thread::sleep_for(1ms); // hack } }); // TODO: exit condition while (true) { CHECK_EMU_STATUS; be_t<u32> get = ctrl->get; be_t<u32> put = ctrl->put; if (put == get || !Emu.IsRunning()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } const u32 cmd = ReadIO32(get); const u32 count = (cmd >> 18) & 0x7ff; if (cmd & CELL_GCM_METHOD_FLAG_JUMP) { u32 offs = cmd & 0x1fffffff; //LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put); ctrl->get = offs; continue; } if (cmd & CELL_GCM_METHOD_FLAG_CALL) { m_call_stack.push(get + 4); u32 offs = cmd & ~3; //LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x", offs, cmd, get); ctrl->get = offs; continue; } if (cmd == CELL_GCM_METHOD_FLAG_RETURN) { u32 get = m_call_stack.top(); m_call_stack.pop(); //LOG_WARNING(RSX, "rsx return(0x%x)", get); ctrl->get = get; continue; } if (cmd == 0) //nop { ctrl->get = get + 4; continue; } auto args = vm::ptr<u32>::make((u32)RSXIOMem.RealAddr(get + 4)); u32 first_cmd = (cmd & 0xffff) >> 2; if (cmd & 0x3) { LOG_WARNING(RSX, "unaligned command: %s (0x%x from 0x%x)", get_method_name(first_cmd).c_str(), first_cmd, cmd & 0xffff); } for (u32 i = 0; i < count; i++) { u32 reg = cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT ? first_cmd : first_cmd + i; u32 value = args[i]; if (rpcs3::config.misc.log.rsx_logging.value()) { LOG_NOTICE(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value); } method_registers[reg] = value; if (capture_current_frame) frame_debug.command_queue.push_back(std::make_pair(reg, value)); if (auto method = methods[reg]) method(this, value); } ctrl->get = get + (count + 1) * 4; } }