Compare commits
25 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d00b7be2d6 | ||
|
|
708e5b027f | ||
|
|
c33c9c76bf | ||
|
|
cad53179ed | ||
|
|
3c313a43fd | ||
|
|
45bdbf538c | ||
|
|
2f2e443858 | ||
|
|
14db101148 | ||
|
|
ea89cf8639 | ||
|
|
5c0a31e29f | ||
|
|
07922abffc | ||
|
|
114a4562ed | ||
|
|
858f8ac6d9 | ||
|
|
b71130e6f1 | ||
|
|
af418eb666 | ||
|
|
a2f6a2480d | ||
|
|
503feba7e4 | ||
|
|
69511aed3d | ||
|
|
a32f6e9d8e | ||
|
|
36df3ce97e | ||
|
|
de2f2e5140 | ||
|
|
72b34650f9 | ||
|
|
105c60b984 | ||
|
|
e609bc1c6a | ||
|
|
017a18f42e |
395
dist/languages/ca.ts
vendored
395
dist/languages/ca.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/cs.ts
vendored
395
dist/languages/cs.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/da.ts
vendored
395
dist/languages/da.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/de.ts
vendored
395
dist/languages/de.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/el.ts
vendored
395
dist/languages/el.ts
vendored
File diff suppressed because it is too large
Load Diff
416
dist/languages/es.ts
vendored
416
dist/languages/es.ts
vendored
File diff suppressed because it is too large
Load Diff
525
dist/languages/fr.ts
vendored
525
dist/languages/fr.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/id.ts
vendored
395
dist/languages/id.ts
vendored
File diff suppressed because it is too large
Load Diff
413
dist/languages/it.ts
vendored
413
dist/languages/it.ts
vendored
File diff suppressed because it is too large
Load Diff
693
dist/languages/ja_JP.ts
vendored
693
dist/languages/ja_JP.ts
vendored
File diff suppressed because it is too large
Load Diff
399
dist/languages/ko_KR.ts
vendored
399
dist/languages/ko_KR.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/nb.ts
vendored
395
dist/languages/nb.ts
vendored
File diff suppressed because it is too large
Load Diff
401
dist/languages/nl.ts
vendored
401
dist/languages/nl.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/pl.ts
vendored
395
dist/languages/pl.ts
vendored
File diff suppressed because it is too large
Load Diff
420
dist/languages/pt_BR.ts
vendored
420
dist/languages/pt_BR.ts
vendored
File diff suppressed because it is too large
Load Diff
417
dist/languages/pt_PT.ts
vendored
417
dist/languages/pt_PT.ts
vendored
File diff suppressed because it is too large
Load Diff
413
dist/languages/ru_RU.ts
vendored
413
dist/languages/ru_RU.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/sv.ts
vendored
395
dist/languages/sv.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/tr_TR.ts
vendored
395
dist/languages/tr_TR.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/vi.ts
vendored
395
dist/languages/vi.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/vi_VN.ts
vendored
395
dist/languages/vi_VN.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/zh_CN.ts
vendored
395
dist/languages/zh_CN.ts
vendored
File diff suppressed because it is too large
Load Diff
395
dist/languages/zh_TW.ts
vendored
395
dist/languages/zh_TW.ts
vendored
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,7 @@ add_library(common STATIC
|
||||
div_ceil.h
|
||||
dynamic_library.cpp
|
||||
dynamic_library.h
|
||||
elf.h
|
||||
error.cpp
|
||||
error.h
|
||||
expected.h
|
||||
|
||||
333
src/common/elf.h
Normal file
333
src/common/elf.h
Normal file
@@ -0,0 +1,333 @@
|
||||
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
|
||||
#include "common_types.h"
|
||||
|
||||
namespace Common {
|
||||
namespace ELF {
|
||||
|
||||
/* Type for a 16-bit quantity. */
|
||||
using Elf32_Half = u16;
|
||||
using Elf64_Half = u16;
|
||||
|
||||
/* Types for signed and unsigned 32-bit quantities. */
|
||||
using Elf32_Word = u32;
|
||||
using Elf32_Sword = s32;
|
||||
using Elf64_Word = u32;
|
||||
using Elf64_Sword = s32;
|
||||
|
||||
/* Types for signed and unsigned 64-bit quantities. */
|
||||
using Elf32_Xword = u64;
|
||||
using Elf32_Sxword = s64;
|
||||
using Elf64_Xword = u64;
|
||||
using Elf64_Sxword = s64;
|
||||
|
||||
/* Type of addresses. */
|
||||
using Elf32_Addr = u32;
|
||||
using Elf64_Addr = u64;
|
||||
|
||||
/* Type of file offsets. */
|
||||
using Elf32_Off = u32;
|
||||
using Elf64_Off = u64;
|
||||
|
||||
/* Type for section indices, which are 16-bit quantities. */
|
||||
using Elf32_Section = u16;
|
||||
using Elf64_Section = u16;
|
||||
|
||||
/* Type for version symbol information. */
|
||||
using Elf32_Versym = Elf32_Half;
|
||||
using Elf64_Versym = Elf64_Half;
|
||||
|
||||
constexpr size_t ElfIdentSize = 16;
|
||||
|
||||
/* The ELF file header. This appears at the start of every ELF file. */
|
||||
|
||||
struct Elf32_Ehdr {
|
||||
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
|
||||
Elf32_Half e_type; /* Object file type */
|
||||
Elf32_Half e_machine; /* Architecture */
|
||||
Elf32_Word e_version; /* Object file version */
|
||||
Elf32_Addr e_entry; /* Entry point virtual address */
|
||||
Elf32_Off e_phoff; /* Program header table file offset */
|
||||
Elf32_Off e_shoff; /* Section header table file offset */
|
||||
Elf32_Word e_flags; /* Processor-specific flags */
|
||||
Elf32_Half e_ehsize; /* ELF header size in bytes */
|
||||
Elf32_Half e_phentsize; /* Program header table entry size */
|
||||
Elf32_Half e_phnum; /* Program header table entry count */
|
||||
Elf32_Half e_shentsize; /* Section header table entry size */
|
||||
Elf32_Half e_shnum; /* Section header table entry count */
|
||||
Elf32_Half e_shstrndx; /* Section header string table index */
|
||||
};
|
||||
|
||||
struct Elf64_Ehdr {
|
||||
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
|
||||
Elf64_Half e_type; /* Object file type */
|
||||
Elf64_Half e_machine; /* Architecture */
|
||||
Elf64_Word e_version; /* Object file version */
|
||||
Elf64_Addr e_entry; /* Entry point virtual address */
|
||||
Elf64_Off e_phoff; /* Program header table file offset */
|
||||
Elf64_Off e_shoff; /* Section header table file offset */
|
||||
Elf64_Word e_flags; /* Processor-specific flags */
|
||||
Elf64_Half e_ehsize; /* ELF header size in bytes */
|
||||
Elf64_Half e_phentsize; /* Program header table entry size */
|
||||
Elf64_Half e_phnum; /* Program header table entry count */
|
||||
Elf64_Half e_shentsize; /* Section header table entry size */
|
||||
Elf64_Half e_shnum; /* Section header table entry count */
|
||||
Elf64_Half e_shstrndx; /* Section header string table index */
|
||||
};
|
||||
|
||||
constexpr u8 ElfClass32 = 1; /* 32-bit objects */
|
||||
constexpr u8 ElfClass64 = 2; /* 64-bit objects */
|
||||
constexpr u8 ElfData2Lsb = 1; /* 2's complement, little endian */
|
||||
constexpr u8 ElfVersionCurrent = 1; /* EV_CURRENT */
|
||||
constexpr u8 ElfOsAbiNone = 0; /* System V ABI */
|
||||
|
||||
constexpr u16 ElfTypeNone = 0; /* No file type */
|
||||
constexpr u16 ElfTypeRel = 0; /* Relocatable file */
|
||||
constexpr u16 ElfTypeExec = 0; /* Executable file */
|
||||
constexpr u16 ElfTypeDyn = 0; /* Shared object file */
|
||||
|
||||
constexpr u16 ElfMachineArm = 40; /* ARM */
|
||||
constexpr u16 ElfMachineAArch64 = 183; /* ARM AARCH64 */
|
||||
|
||||
constexpr std::array<u8, ElfIdentSize> Elf32Ident{
|
||||
0x7f, 'E', 'L', 'F', ElfClass32, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
|
||||
|
||||
constexpr std::array<u8, ElfIdentSize> Elf64Ident{
|
||||
0x7f, 'E', 'L', 'F', ElfClass64, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
|
||||
|
||||
/* Section header. */
|
||||
|
||||
struct Elf32_Shdr {
|
||||
Elf32_Word sh_name; /* Section name (string tbl index) */
|
||||
Elf32_Word sh_type; /* Section type */
|
||||
Elf32_Word sh_flags; /* Section flags */
|
||||
Elf32_Addr sh_addr; /* Section virtual addr at execution */
|
||||
Elf32_Off sh_offset; /* Section file offset */
|
||||
Elf32_Word sh_size; /* Section size in bytes */
|
||||
Elf32_Word sh_link; /* Link to another section */
|
||||
Elf32_Word sh_info; /* Additional section information */
|
||||
Elf32_Word sh_addralign; /* Section alignment */
|
||||
Elf32_Word sh_entsize; /* Entry size if section holds table */
|
||||
};
|
||||
|
||||
struct Elf64_Shdr {
|
||||
Elf64_Word sh_name; /* Section name (string tbl index) */
|
||||
Elf64_Word sh_type; /* Section type */
|
||||
Elf64_Xword sh_flags; /* Section flags */
|
||||
Elf64_Addr sh_addr; /* Section virtual addr at execution */
|
||||
Elf64_Off sh_offset; /* Section file offset */
|
||||
Elf64_Xword sh_size; /* Section size in bytes */
|
||||
Elf64_Word sh_link; /* Link to another section */
|
||||
Elf64_Word sh_info; /* Additional section information */
|
||||
Elf64_Xword sh_addralign; /* Section alignment */
|
||||
Elf64_Xword sh_entsize; /* Entry size if section holds table */
|
||||
};
|
||||
|
||||
constexpr u32 ElfShnUndef = 0; /* Undefined section */
|
||||
|
||||
constexpr u32 ElfShtNull = 0; /* Section header table entry unused */
|
||||
constexpr u32 ElfShtProgBits = 1; /* Program data */
|
||||
constexpr u32 ElfShtSymtab = 2; /* Symbol table */
|
||||
constexpr u32 ElfShtStrtab = 3; /* String table */
|
||||
constexpr u32 ElfShtRela = 4; /* Relocation entries with addends */
|
||||
constexpr u32 ElfShtDynamic = 6; /* Dynamic linking information */
|
||||
constexpr u32 ElfShtNobits = 7; /* Program space with no data (bss) */
|
||||
constexpr u32 ElfShtRel = 9; /* Relocation entries, no addends */
|
||||
constexpr u32 ElfShtDynsym = 11; /* Dynamic linker symbol table */
|
||||
|
||||
/* Symbol table entry. */
|
||||
|
||||
struct Elf32_Sym {
|
||||
Elf32_Word st_name; /* Symbol name (string tbl index) */
|
||||
Elf32_Addr st_value; /* Symbol value */
|
||||
Elf32_Word st_size; /* Symbol size */
|
||||
u8 st_info; /* Symbol type and binding */
|
||||
u8 st_other; /* Symbol visibility */
|
||||
Elf32_Section st_shndx; /* Section index */
|
||||
};
|
||||
|
||||
struct Elf64_Sym {
|
||||
Elf64_Word st_name; /* Symbol name (string tbl index) */
|
||||
u8 st_info; /* Symbol type and binding */
|
||||
u8 st_other; /* Symbol visibility */
|
||||
Elf64_Section st_shndx; /* Section index */
|
||||
Elf64_Addr st_value; /* Symbol value */
|
||||
Elf64_Xword st_size; /* Symbol size */
|
||||
};
|
||||
|
||||
/* How to extract and insert information held in the st_info field. */
|
||||
|
||||
static inline u8 ElfStBind(u8 st_info) {
|
||||
return st_info >> 4;
|
||||
}
|
||||
static inline u8 ElfStType(u8 st_info) {
|
||||
return st_info & 0xf;
|
||||
}
|
||||
static inline u8 ElfStInfo(u8 st_bind, u8 st_type) {
|
||||
return static_cast<u8>((st_bind << 4) + (st_type & 0xf));
|
||||
}
|
||||
|
||||
constexpr u8 ElfBindLocal = 0; /* Local symbol */
|
||||
constexpr u8 ElfBindGlobal = 1; /* Global symbol */
|
||||
constexpr u8 ElfBindWeak = 2; /* Weak symbol */
|
||||
|
||||
constexpr u8 ElfTypeUnspec = 0; /* Symbol type is unspecified */
|
||||
constexpr u8 ElfTypeObject = 1; /* Symbol is a data object */
|
||||
constexpr u8 ElfTypeFunc = 2; /* Symbol is a code object */
|
||||
|
||||
static inline u8 ElfStVisibility(u8 st_other) {
|
||||
return static_cast<u8>(st_other & 0x3);
|
||||
}
|
||||
|
||||
constexpr u8 ElfVisibilityDefault = 0; /* Default symbol visibility rules */
|
||||
constexpr u8 ElfVisibilityInternal = 1; /* Processor specific hidden class */
|
||||
constexpr u8 ElfVisibilityHidden = 2; /* Sym unavailable in other modules */
|
||||
constexpr u8 ElfVisibilityProtected = 3; /* Not preemptible, not exported */
|
||||
|
||||
/* Relocation table entry without addend (in section of type ShtRel). */
|
||||
|
||||
struct Elf32_Rel {
|
||||
Elf32_Addr r_offset; /* Address */
|
||||
Elf32_Word r_info; /* Relocation type and symbol index */
|
||||
};
|
||||
|
||||
/* Relocation table entry with addend (in section of type ShtRela). */
|
||||
|
||||
struct Elf32_Rela {
|
||||
Elf32_Addr r_offset; /* Address */
|
||||
Elf32_Word r_info; /* Relocation type and symbol index */
|
||||
Elf32_Sword r_addend; /* Addend */
|
||||
};
|
||||
|
||||
struct Elf64_Rela {
|
||||
Elf64_Addr r_offset; /* Address */
|
||||
Elf64_Xword r_info; /* Relocation type and symbol index */
|
||||
Elf64_Sxword r_addend; /* Addend */
|
||||
};
|
||||
|
||||
/* How to extract and insert information held in the r_info field. */
|
||||
|
||||
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
|
||||
return r_info >> 8;
|
||||
}
|
||||
static inline u8 Elf32RelType(Elf32_Word r_info) {
|
||||
return static_cast<u8>(r_info & 0xff);
|
||||
}
|
||||
static inline Elf32_Word Elf32RelInfo(u32 sym_index, u8 type) {
|
||||
return (sym_index << 8) + type;
|
||||
}
|
||||
static inline u32 Elf64RelSymIndex(Elf64_Xword r_info) {
|
||||
return static_cast<u32>(r_info >> 32);
|
||||
}
|
||||
static inline u32 Elf64RelType(Elf64_Xword r_info) {
|
||||
return r_info & 0xffffffff;
|
||||
}
|
||||
static inline Elf64_Xword Elf64RelInfo(u32 sym_index, u32 type) {
|
||||
return (static_cast<Elf64_Xword>(sym_index) << 32) + type;
|
||||
}
|
||||
|
||||
constexpr u32 ElfArmCopy = 20; /* Copy symbol at runtime */
|
||||
constexpr u32 ElfArmGlobDat = 21; /* Create GOT entry */
|
||||
constexpr u32 ElfArmJumpSlot = 22; /* Create PLT entry */
|
||||
constexpr u32 ElfArmRelative = 23; /* Adjust by program base */
|
||||
|
||||
constexpr u32 ElfAArch64Copy = 1024; /* Copy symbol at runtime */
|
||||
constexpr u32 ElfAArch64GlobDat = 1025; /* Create GOT entry */
|
||||
constexpr u32 ElfAArch64JumpSlot = 1026; /* Create PLT entry */
|
||||
constexpr u32 ElfAArch64Relative = 1027; /* Adjust by program base */
|
||||
|
||||
/* Program segment header. */
|
||||
|
||||
struct Elf32_Phdr {
|
||||
Elf32_Word p_type; /* Segment type */
|
||||
Elf32_Off p_offset; /* Segment file offset */
|
||||
Elf32_Addr p_vaddr; /* Segment virtual address */
|
||||
Elf32_Addr p_paddr; /* Segment physical address */
|
||||
Elf32_Word p_filesz; /* Segment size in file */
|
||||
Elf32_Word p_memsz; /* Segment size in memory */
|
||||
Elf32_Word p_flags; /* Segment flags */
|
||||
Elf32_Word p_align; /* Segment alignment */
|
||||
};
|
||||
|
||||
struct Elf64_Phdr {
|
||||
Elf64_Word p_type; /* Segment type */
|
||||
Elf64_Word p_flags; /* Segment flags */
|
||||
Elf64_Off p_offset; /* Segment file offset */
|
||||
Elf64_Addr p_vaddr; /* Segment virtual address */
|
||||
Elf64_Addr p_paddr; /* Segment physical address */
|
||||
Elf64_Xword p_filesz; /* Segment size in file */
|
||||
Elf64_Xword p_memsz; /* Segment size in memory */
|
||||
Elf64_Xword p_align; /* Segment alignment */
|
||||
};
|
||||
|
||||
/* Legal values for p_type (segment type). */
|
||||
|
||||
constexpr u32 ElfPtNull = 0; /* Program header table entry unused */
|
||||
constexpr u32 ElfPtLoad = 1; /* Loadable program segment */
|
||||
constexpr u32 ElfPtDynamic = 2; /* Dynamic linking information */
|
||||
constexpr u32 ElfPtInterp = 3; /* Program interpreter */
|
||||
constexpr u32 ElfPtNote = 4; /* Auxiliary information */
|
||||
constexpr u32 ElfPtPhdr = 6; /* Entry for header table itself */
|
||||
constexpr u32 ElfPtTls = 7; /* Thread-local storage segment */
|
||||
|
||||
/* Legal values for p_flags (segment flags). */
|
||||
|
||||
constexpr u32 ElfPfExec = 0; /* Segment is executable */
|
||||
constexpr u32 ElfPfWrite = 1; /* Segment is writable */
|
||||
constexpr u32 ElfPfRead = 2; /* Segment is readable */
|
||||
|
||||
/* Dynamic section entry. */
|
||||
|
||||
struct Elf32_Dyn {
|
||||
Elf32_Sword d_tag; /* Dynamic entry type */
|
||||
union {
|
||||
Elf32_Word d_val; /* Integer value */
|
||||
Elf32_Addr d_ptr; /* Address value */
|
||||
} d_un;
|
||||
};
|
||||
|
||||
struct Elf64_Dyn {
|
||||
Elf64_Sxword d_tag; /* Dynamic entry type */
|
||||
union {
|
||||
Elf64_Xword d_val; /* Integer value */
|
||||
Elf64_Addr d_ptr; /* Address value */
|
||||
} d_un;
|
||||
};
|
||||
|
||||
/* Legal values for d_tag (dynamic entry type). */
|
||||
|
||||
constexpr u32 ElfDtNull = 0; /* Marks end of dynamic section */
|
||||
constexpr u32 ElfDtNeeded = 1; /* Name of needed library */
|
||||
constexpr u32 ElfDtPltRelSz = 2; /* Size in bytes of PLT relocs */
|
||||
constexpr u32 ElfDtPltGot = 3; /* Processor defined value */
|
||||
constexpr u32 ElfDtHash = 4; /* Address of symbol hash table */
|
||||
constexpr u32 ElfDtStrtab = 5; /* Address of string table */
|
||||
constexpr u32 ElfDtSymtab = 6; /* Address of symbol table */
|
||||
constexpr u32 ElfDtRela = 7; /* Address of Rela relocs */
|
||||
constexpr u32 ElfDtRelasz = 8; /* Total size of Rela relocs */
|
||||
constexpr u32 ElfDtRelaent = 9; /* Size of one Rela reloc */
|
||||
constexpr u32 ElfDtStrsz = 10; /* Size of string table */
|
||||
constexpr u32 ElfDtSyment = 11; /* Size of one symbol table entry */
|
||||
constexpr u32 ElfDtInit = 12; /* Address of init function */
|
||||
constexpr u32 ElfDtFini = 13; /* Address of termination function */
|
||||
constexpr u32 ElfDtRel = 17; /* Address of Rel relocs */
|
||||
constexpr u32 ElfDtRelsz = 18; /* Total size of Rel relocs */
|
||||
constexpr u32 ElfDtRelent = 19; /* Size of one Rel reloc */
|
||||
constexpr u32 ElfDtPltRel = 20; /* Type of reloc in PLT */
|
||||
constexpr u32 ElfDtTextRel = 22; /* Reloc might modify .text */
|
||||
constexpr u32 ElfDtJmpRel = 23; /* Address of PLT relocs */
|
||||
constexpr u32 ElfDtBindNow = 24; /* Process relocations of object */
|
||||
constexpr u32 ElfDtInitArray = 25; /* Array with addresses of init fct */
|
||||
constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
|
||||
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
|
||||
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
|
||||
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
|
||||
|
||||
} // namespace ELF
|
||||
} // namespace Common
|
||||
@@ -3,73 +3,14 @@
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/elf.h"
|
||||
#include "core/arm/symbols.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
using namespace Common::ELF;
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
|
||||
constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
|
||||
constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
|
||||
constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
|
||||
constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
|
||||
|
||||
enum class ELFSymbolType : u8 {
|
||||
None = 0,
|
||||
Object = 1,
|
||||
Function = 2,
|
||||
Section = 3,
|
||||
File = 4,
|
||||
Common = 5,
|
||||
TLS = 6,
|
||||
};
|
||||
|
||||
enum class ELFSymbolBinding : u8 {
|
||||
Local = 0,
|
||||
Global = 1,
|
||||
Weak = 2,
|
||||
};
|
||||
|
||||
enum class ELFSymbolVisibility : u8 {
|
||||
Default = 0,
|
||||
Internal = 1,
|
||||
Hidden = 2,
|
||||
Protected = 3,
|
||||
};
|
||||
|
||||
struct ELF64Symbol {
|
||||
u32 name_index;
|
||||
union {
|
||||
u8 info;
|
||||
|
||||
BitField<0, 4, ELFSymbolType> type;
|
||||
BitField<4, 4, ELFSymbolBinding> binding;
|
||||
};
|
||||
ELFSymbolVisibility visibility;
|
||||
u16 sh_index;
|
||||
u64 value;
|
||||
u64 size;
|
||||
};
|
||||
static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size.");
|
||||
|
||||
struct ELF32Symbol {
|
||||
u32 name_index;
|
||||
u32 value;
|
||||
u32 size;
|
||||
union {
|
||||
u8 info;
|
||||
|
||||
BitField<0, 4, ELFSymbolType> type;
|
||||
BitField<4, 4, ELFSymbolBinding> binding;
|
||||
};
|
||||
ELFSymbolVisibility visibility;
|
||||
u16 sh_index;
|
||||
};
|
||||
static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size.");
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace Symbols {
|
||||
|
||||
template <typename Word, typename ELFSymbol, typename ByteReader>
|
||||
@@ -110,15 +51,15 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
|
||||
const Word value = ReadWord(dynamic_index + sizeof(Word));
|
||||
dynamic_index += 2 * sizeof(Word);
|
||||
|
||||
if (tag == ELF_DYNAMIC_TAG_NULL) {
|
||||
if (tag == ElfDtNull) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag == ELF_DYNAMIC_TAG_STRTAB) {
|
||||
if (tag == ElfDtStrtab) {
|
||||
string_table_offset = value;
|
||||
} else if (tag == ELF_DYNAMIC_TAG_SYMTAB) {
|
||||
} else if (tag == ElfDtSymtab) {
|
||||
symbol_table_offset = value;
|
||||
} else if (tag == ELF_DYNAMIC_TAG_SYMENT) {
|
||||
} else if (tag == ElfDtSyment) {
|
||||
symbol_entry_size = value;
|
||||
}
|
||||
}
|
||||
@@ -134,14 +75,14 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
|
||||
ELFSymbol symbol{};
|
||||
ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol));
|
||||
|
||||
VAddr string_offset = string_table_offset + symbol.name_index;
|
||||
VAddr string_offset = string_table_offset + symbol.st_name;
|
||||
std::string name;
|
||||
for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) {
|
||||
name += static_cast<char>(c);
|
||||
}
|
||||
|
||||
symbol_index += symbol_entry_size;
|
||||
out[name] = std::make_pair(symbol.value, symbol.size);
|
||||
out[name] = std::make_pair(symbol.st_value, symbol.st_size);
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -152,9 +93,9 @@ Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
|
||||
[&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }};
|
||||
|
||||
if (is_64) {
|
||||
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
|
||||
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
|
||||
} else {
|
||||
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
|
||||
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,9 +105,9 @@ Symbols GetSymbols(std::span<const u8> data, bool is_64) {
|
||||
}};
|
||||
|
||||
if (is_64) {
|
||||
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
|
||||
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
|
||||
} else {
|
||||
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
|
||||
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,15 +20,16 @@ template <typename Readable, typename Buffer, typename Callback>
|
||||
static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
|
||||
static_assert(std::is_trivial_v<Buffer>);
|
||||
auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))};
|
||||
r.async_read_some(boost_buffer, [&](const boost::system::error_code& error, size_t bytes_read) {
|
||||
if (!error.failed()) {
|
||||
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
|
||||
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
|
||||
c(received_data);
|
||||
}
|
||||
r.async_read_some(
|
||||
boost_buffer, [&, c](const boost::system::error_code& error, size_t bytes_read) {
|
||||
if (!error.failed()) {
|
||||
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
|
||||
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
|
||||
c(received_data);
|
||||
}
|
||||
|
||||
AsyncReceiveInto(r, buffer, c);
|
||||
});
|
||||
AsyncReceiveInto(r, buffer, c);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Readable, typename Buffer>
|
||||
@@ -51,7 +52,7 @@ public:
|
||||
InitializeServer(port);
|
||||
}
|
||||
|
||||
~DebuggerImpl() {
|
||||
~DebuggerImpl() override {
|
||||
ShutdownServer();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ enum class DebuggerAction {
|
||||
|
||||
class DebuggerBackend {
|
||||
public:
|
||||
virtual ~DebuggerBackend() = default;
|
||||
|
||||
/**
|
||||
* Can be invoked from a callback to synchronously wait for more data.
|
||||
* Will return as soon as least one byte is received. Reads up to 4096 bytes.
|
||||
@@ -52,6 +54,8 @@ class DebuggerFrontend {
|
||||
public:
|
||||
explicit DebuggerFrontend(DebuggerBackend& backend_) : backend{backend_} {}
|
||||
|
||||
virtual ~DebuggerFrontend() = default;
|
||||
|
||||
/**
|
||||
* Called after the client has successfully connected to the port.
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,65 @@ constexpr char GDB_STUB_REPLY_ERR[] = "E01";
|
||||
constexpr char GDB_STUB_REPLY_OK[] = "OK";
|
||||
constexpr char GDB_STUB_REPLY_EMPTY[] = "";
|
||||
|
||||
static u8 CalculateChecksum(std::string_view data) {
|
||||
return std::accumulate(data.begin(), data.end(), u8{0},
|
||||
[](u8 lhs, u8 rhs) { return static_cast<u8>(lhs + rhs); });
|
||||
}
|
||||
|
||||
static std::string EscapeGDB(std::string_view data) {
|
||||
std::string escaped;
|
||||
escaped.reserve(data.size());
|
||||
|
||||
for (char c : data) {
|
||||
switch (c) {
|
||||
case '#':
|
||||
escaped += "}\x03";
|
||||
break;
|
||||
case '$':
|
||||
escaped += "}\x04";
|
||||
break;
|
||||
case '*':
|
||||
escaped += "}\x0a";
|
||||
break;
|
||||
case '}':
|
||||
escaped += "}\x5d";
|
||||
break;
|
||||
default:
|
||||
escaped += c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return escaped;
|
||||
}
|
||||
|
||||
static std::string EscapeXML(std::string_view data) {
|
||||
std::string escaped;
|
||||
escaped.reserve(data.size());
|
||||
|
||||
for (char c : data) {
|
||||
switch (c) {
|
||||
case '&':
|
||||
escaped += "&";
|
||||
break;
|
||||
case '"':
|
||||
escaped += """;
|
||||
break;
|
||||
case '<':
|
||||
escaped += "<";
|
||||
break;
|
||||
case '>':
|
||||
escaped += ">";
|
||||
break;
|
||||
default:
|
||||
escaped += c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return escaped;
|
||||
}
|
||||
|
||||
GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_)
|
||||
: DebuggerFrontend(backend_), system{system_} {
|
||||
if (system.CurrentProcess()->Is64BitProcess()) {
|
||||
@@ -255,6 +314,80 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
|
||||
}
|
||||
}
|
||||
|
||||
// Structure offsets are from Atmosphere
|
||||
// See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp
|
||||
|
||||
static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
|
||||
const Kernel::KThread* thread) {
|
||||
// Read thread type from TLS
|
||||
const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)};
|
||||
const VAddr argument_thread_type{thread->GetArgument()};
|
||||
|
||||
if (argument_thread_type && tls_thread_type != argument_thread_type) {
|
||||
// Probably not created by nnsdk, no name available.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!tls_thread_type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const u16 version{memory.Read16(tls_thread_type + 0x26)};
|
||||
VAddr name_pointer{};
|
||||
if (version == 1) {
|
||||
name_pointer = memory.Read32(tls_thread_type + 0xe4);
|
||||
} else {
|
||||
name_pointer = memory.Read32(tls_thread_type + 0xe8);
|
||||
}
|
||||
|
||||
if (!name_pointer) {
|
||||
// No name provided.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return memory.ReadCString(name_pointer, 256);
|
||||
}
|
||||
|
||||
static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
|
||||
const Kernel::KThread* thread) {
|
||||
// Read thread type from TLS
|
||||
const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)};
|
||||
const VAddr argument_thread_type{thread->GetArgument()};
|
||||
|
||||
if (argument_thread_type && tls_thread_type != argument_thread_type) {
|
||||
// Probably not created by nnsdk, no name available.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!tls_thread_type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const u16 version{memory.Read16(tls_thread_type + 0x46)};
|
||||
VAddr name_pointer{};
|
||||
if (version == 1) {
|
||||
name_pointer = memory.Read64(tls_thread_type + 0x1a0);
|
||||
} else {
|
||||
name_pointer = memory.Read64(tls_thread_type + 0x1a8);
|
||||
}
|
||||
|
||||
if (!name_pointer) {
|
||||
// No name provided.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return memory.ReadCString(name_pointer, 256);
|
||||
}
|
||||
|
||||
static std::optional<std::string> GetThreadName(Core::System& system,
|
||||
const Kernel::KThread* thread) {
|
||||
if (system.CurrentProcess()->Is64BitProcess()) {
|
||||
return GetNameFromThreadType64(system.Memory(), thread);
|
||||
} else {
|
||||
return GetNameFromThreadType32(system.Memory(), thread);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) {
|
||||
switch (thread->GetWaitReasonForDebugging()) {
|
||||
case Kernel::ThreadWaitReasonForDebugging::Sleep:
|
||||
@@ -289,6 +422,18 @@ static std::string GetThreadState(const Kernel::KThread* thread) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string PaginateBuffer(std::string_view buffer, std::string_view request) {
|
||||
const auto amount{request.substr(request.find(',') + 1)};
|
||||
const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))};
|
||||
const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
|
||||
|
||||
if (offset_val + amount_val > buffer.size()) {
|
||||
return fmt::format("l{}", buffer.substr(offset_val));
|
||||
} else {
|
||||
return fmt::format("m{}", buffer.substr(offset_val, amount_val));
|
||||
}
|
||||
}
|
||||
|
||||
void GDBStub::HandleQuery(std::string_view command) {
|
||||
if (command.starts_with("TStatus")) {
|
||||
// no tracepoint support
|
||||
@@ -297,18 +442,8 @@ void GDBStub::HandleQuery(std::string_view command) {
|
||||
SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;"
|
||||
"vContSupported+;QStartNoAckMode+");
|
||||
} else if (command.starts_with("Xfer:features:read:target.xml:")) {
|
||||
const auto offset{command.substr(30)};
|
||||
const auto amount{command.substr(command.find(',') + 1)};
|
||||
|
||||
const auto offset_val{static_cast<u64>(strtoll(offset.data(), nullptr, 16))};
|
||||
const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
|
||||
const auto target_xml{arch->GetTargetXML()};
|
||||
|
||||
if (offset_val + amount_val > target_xml.size()) {
|
||||
SendReply("l" + target_xml.substr(offset_val));
|
||||
} else {
|
||||
SendReply("m" + target_xml.substr(offset_val, amount_val));
|
||||
}
|
||||
SendReply(PaginateBuffer(target_xml, command.substr(30)));
|
||||
} else if (command.starts_with("Offsets")) {
|
||||
Loader::AppLoader::Modules modules;
|
||||
system.GetAppLoader().ReadNSOModules(modules);
|
||||
@@ -321,6 +456,20 @@ void GDBStub::HandleQuery(std::string_view command) {
|
||||
SendReply(fmt::format("TextSeg={:x}",
|
||||
system.CurrentProcess()->PageTable().GetCodeRegionStart()));
|
||||
}
|
||||
} else if (command.starts_with("Xfer:libraries:read::")) {
|
||||
Loader::AppLoader::Modules modules;
|
||||
system.GetAppLoader().ReadNSOModules(modules);
|
||||
|
||||
std::string buffer;
|
||||
buffer += R"(<?xml version="1.0"?>)";
|
||||
buffer += "<library-list>";
|
||||
for (const auto& [base, name] : modules) {
|
||||
buffer += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)",
|
||||
EscapeXML(name), base);
|
||||
}
|
||||
buffer += "</library-list>";
|
||||
|
||||
SendReply(PaginateBuffer(buffer, command.substr(21)));
|
||||
} else if (command.starts_with("fThreadInfo")) {
|
||||
// beginning of list
|
||||
const auto& threads = system.GlobalSchedulerContext().GetThreadList();
|
||||
@@ -332,20 +481,26 @@ void GDBStub::HandleQuery(std::string_view command) {
|
||||
} else if (command.starts_with("sThreadInfo")) {
|
||||
// end of list
|
||||
SendReply("l");
|
||||
} else if (command.starts_with("Xfer:threads:read")) {
|
||||
} else if (command.starts_with("Xfer:threads:read::")) {
|
||||
std::string buffer;
|
||||
buffer += R"(l<?xml version="1.0"?>)";
|
||||
buffer += R"(<?xml version="1.0"?>)";
|
||||
buffer += "<threads>";
|
||||
|
||||
const auto& threads = system.GlobalSchedulerContext().GetThreadList();
|
||||
for (const auto& thread : threads) {
|
||||
buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="Thread {:d}">{}</thread>)",
|
||||
for (const auto* thread : threads) {
|
||||
auto thread_name{GetThreadName(system, thread)};
|
||||
if (!thread_name) {
|
||||
thread_name = fmt::format("Thread {:d}", thread->GetThreadID());
|
||||
}
|
||||
|
||||
buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)",
|
||||
thread->GetThreadID(), thread->GetActiveCore(),
|
||||
thread->GetThreadID(), GetThreadState(thread));
|
||||
EscapeXML(*thread_name), GetThreadState(thread));
|
||||
}
|
||||
|
||||
buffer += "</threads>";
|
||||
SendReply(buffer);
|
||||
|
||||
SendReply(PaginateBuffer(buffer, command.substr(19)));
|
||||
} else if (command.starts_with("Attached")) {
|
||||
SendReply("0");
|
||||
} else if (command.starts_with("StartNoAckMode")) {
|
||||
@@ -438,14 +593,10 @@ std::optional<std::string> GDBStub::DetachCommand() {
|
||||
return data.substr(1, data.size() - 4);
|
||||
}
|
||||
|
||||
u8 GDBStub::CalculateChecksum(std::string_view data) {
|
||||
return static_cast<u8>(
|
||||
std::accumulate(data.begin(), data.end(), u8{0}, [](u8 lhs, u8 rhs) { return lhs + rhs; }));
|
||||
}
|
||||
|
||||
void GDBStub::SendReply(std::string_view data) {
|
||||
const auto output{
|
||||
fmt::format("{}{}{}{:02x}", GDB_STUB_START, data, GDB_STUB_END, CalculateChecksum(data))};
|
||||
const auto escaped{EscapeGDB(data)};
|
||||
const auto output{fmt::format("{}{}{}{:02x}", GDB_STUB_START, escaped, GDB_STUB_END,
|
||||
CalculateChecksum(escaped))};
|
||||
LOG_TRACE(Debug_GDBStub, "Writing reply: {}", output);
|
||||
|
||||
// C++ string support is complete rubbish
|
||||
|
||||
@@ -19,7 +19,7 @@ class System;
|
||||
class GDBStub : public DebuggerFrontend {
|
||||
public:
|
||||
explicit GDBStub(DebuggerBackend& backend, Core::System& system);
|
||||
~GDBStub();
|
||||
~GDBStub() override;
|
||||
|
||||
void Connected() override;
|
||||
void Stopped(Kernel::KThread* thread) override;
|
||||
@@ -34,7 +34,6 @@ private:
|
||||
std::optional<std::string> DetachCommand();
|
||||
Kernel::KThread* GetThreadByID(u64 thread_id);
|
||||
|
||||
static u8 CalculateChecksum(std::string_view data);
|
||||
void SendReply(std::string_view data);
|
||||
void SendStatus(char status);
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ std::string GDBStubA64::GetTargetXML() const {
|
||||
R"(<?xml version="1.0"?>
|
||||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||||
<target version="1.0">
|
||||
<architecture>aarch64</architecture>
|
||||
<feature name="org.gnu.gdb.aarch64.core">
|
||||
<reg name="x0" bitsize="64"/>
|
||||
<reg name="x1" bitsize="64"/>
|
||||
@@ -80,7 +81,7 @@ std::string GDBStubA64::GetTargetXML() const {
|
||||
<reg name="x30" bitsize="64"/>
|
||||
<reg name="sp" bitsize="64" type="data_ptr"/>
|
||||
<reg name="pc" bitsize="64" type="code_ptr"/>
|
||||
<flags id="pstate_flags" size="4">
|
||||
<flags id="cpsr_flags" size="4">
|
||||
<field name="SP" start="0" end="0"/>
|
||||
<field name="" start="1" end="1"/>
|
||||
<field name="EL" start="2" end="3"/>
|
||||
@@ -97,9 +98,84 @@ std::string GDBStubA64::GetTargetXML() const {
|
||||
<field name="Z" start="30" end="30"/>
|
||||
<field name="N" start="31" end="31"/>
|
||||
</flags>
|
||||
<reg name="pstate" bitsize="32" type="pstate_flags"/>
|
||||
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
|
||||
</feature>
|
||||
<feature name="org.gnu.gdb.aarch64.fpu">
|
||||
<vector id="v2d" type="ieee_double" count="2"/>
|
||||
<vector id="v2u" type="uint64" count="2"/>
|
||||
<vector id="v2i" type="int64" count="2"/>
|
||||
<vector id="v4f" type="ieee_single" count="4"/>
|
||||
<vector id="v4u" type="uint32" count="4"/>
|
||||
<vector id="v4i" type="int32" count="4"/>
|
||||
<vector id="v8u" type="uint16" count="8"/>
|
||||
<vector id="v8i" type="int16" count="8"/>
|
||||
<vector id="v16u" type="uint8" count="16"/>
|
||||
<vector id="v16i" type="int8" count="16"/>
|
||||
<vector id="v1u" type="uint128" count="1"/>
|
||||
<vector id="v1i" type="int128" count="1"/>
|
||||
<union id="vnd">
|
||||
<field name="f" type="v2d"/>
|
||||
<field name="u" type="v2u"/>
|
||||
<field name="s" type="v2i"/>
|
||||
</union>
|
||||
<union id="vns">
|
||||
<field name="f" type="v4f"/>
|
||||
<field name="u" type="v4u"/>
|
||||
<field name="s" type="v4i"/>
|
||||
</union>
|
||||
<union id="vnh">
|
||||
<field name="u" type="v8u"/>
|
||||
<field name="s" type="v8i"/>
|
||||
</union>
|
||||
<union id="vnb">
|
||||
<field name="u" type="v16u"/>
|
||||
<field name="s" type="v16i"/>
|
||||
</union>
|
||||
<union id="vnq">
|
||||
<field name="u" type="v1u"/>
|
||||
<field name="s" type="v1i"/>
|
||||
</union>
|
||||
<union id="aarch64v">
|
||||
<field name="d" type="vnd"/>
|
||||
<field name="s" type="vns"/>
|
||||
<field name="h" type="vnh"/>
|
||||
<field name="b" type="vnb"/>
|
||||
<field name="q" type="vnq"/>
|
||||
</union>
|
||||
<reg name="v0" bitsize="128" type="aarch64v" regnum="34"/>
|
||||
<reg name="v1" bitsize="128" type="aarch64v" />
|
||||
<reg name="v2" bitsize="128" type="aarch64v" />
|
||||
<reg name="v3" bitsize="128" type="aarch64v" />
|
||||
<reg name="v4" bitsize="128" type="aarch64v" />
|
||||
<reg name="v5" bitsize="128" type="aarch64v" />
|
||||
<reg name="v6" bitsize="128" type="aarch64v" />
|
||||
<reg name="v7" bitsize="128" type="aarch64v" />
|
||||
<reg name="v8" bitsize="128" type="aarch64v" />
|
||||
<reg name="v9" bitsize="128" type="aarch64v" />
|
||||
<reg name="v10" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v11" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v12" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v13" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v14" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v15" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v16" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v17" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v18" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v19" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v20" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v21" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v22" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v23" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v24" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v25" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v26" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v27" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v28" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v29" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v30" bitsize="128" type="aarch64v"/>
|
||||
<reg name="v31" bitsize="128" type="aarch64v"/>
|
||||
<reg name="fpsr" bitsize="32"/>
|
||||
<reg name="fpcr" bitsize="32"/>
|
||||
</feature>
|
||||
</target>)";
|
||||
|
||||
@@ -121,12 +197,12 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const
|
||||
return ValueToHex(context.pc);
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
return ValueToHex(context.pstate);
|
||||
} else if (id >= Q0_REGISTER && id < FPCR_REGISTER) {
|
||||
} else if (id >= Q0_REGISTER && id < FPSR_REGISTER) {
|
||||
return ValueToHex(fprs[id - Q0_REGISTER]);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
return ValueToHex(context.fpcr);
|
||||
} else if (id == FPSR_REGISTER) {
|
||||
return ValueToHex(context.fpsr);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
return ValueToHex(context.fpcr);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
@@ -145,12 +221,12 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
|
||||
context.pc = HexToValue<u64>(value);
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
context.pstate = HexToValue<u32>(value);
|
||||
} else if (id >= Q0_REGISTER && id < FPCR_REGISTER) {
|
||||
} else if (id >= Q0_REGISTER && id < FPSR_REGISTER) {
|
||||
context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
context.fpcr = HexToValue<u32>(value);
|
||||
} else if (id == FPSR_REGISTER) {
|
||||
context.fpsr = HexToValue<u32>(value);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
context.fpcr = HexToValue<u32>(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +271,7 @@ std::string GDBStubA32::GetTargetXML() const {
|
||||
R"(<?xml version="1.0"?>
|
||||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||||
<target version="1.0">
|
||||
<architecture>arm</architecture>
|
||||
<feature name="org.gnu.gdb.arm.core">
|
||||
<reg name="r0" bitsize="32" type="uint32"/>
|
||||
<reg name="r1" bitsize="32" type="uint32"/>
|
||||
|
||||
@@ -40,8 +40,8 @@ private:
|
||||
static constexpr u32 PC_REGISTER = 32;
|
||||
static constexpr u32 PSTATE_REGISTER = 33;
|
||||
static constexpr u32 Q0_REGISTER = 34;
|
||||
static constexpr u32 FPCR_REGISTER = 66;
|
||||
static constexpr u32 FPSR_REGISTER = 67;
|
||||
static constexpr u32 FPSR_REGISTER = 66;
|
||||
static constexpr u32 FPCR_REGISTER = 67;
|
||||
};
|
||||
|
||||
class GDBStubA32 final : public GDBStubArch {
|
||||
|
||||
@@ -198,6 +198,10 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
|
||||
resource_limit_release_hint = false;
|
||||
cpu_time = 0;
|
||||
|
||||
// Set debug context.
|
||||
stack_top = user_stack_top;
|
||||
argument = arg;
|
||||
|
||||
// Clear our stack parameters.
|
||||
std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0,
|
||||
sizeof(StackParameters));
|
||||
|
||||
@@ -660,6 +660,14 @@ public:
|
||||
void IfDummyThreadTryWait();
|
||||
void IfDummyThreadEndWait();
|
||||
|
||||
[[nodiscard]] uintptr_t GetArgument() const {
|
||||
return argument;
|
||||
}
|
||||
|
||||
[[nodiscard]] VAddr GetUserStackTop() const {
|
||||
return stack_top;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t PriorityInheritanceCountMax = 10;
|
||||
union SyncObjectBuffer {
|
||||
@@ -791,6 +799,8 @@ private:
|
||||
std::vector<KSynchronizationObject*> wait_objects_for_debugging;
|
||||
VAddr mutex_wait_address_for_debugging{};
|
||||
ThreadWaitReasonForDebugging wait_reason_for_debugging{};
|
||||
uintptr_t argument;
|
||||
VAddr stack_top;
|
||||
|
||||
public:
|
||||
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
|
||||
namespace Service::HID {
|
||||
@@ -38,21 +40,32 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_IRS, "called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -60,35 +73,109 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedMomentProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedClusteringProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedImageTransferProcessorConfig processor_config;
|
||||
u32 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem =
|
||||
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -97,71 +184,195 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedTeraPluginProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.mode,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
|
||||
npad_id != Core::HID::NpadIdType::Handheld) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidNpadId);
|
||||
return;
|
||||
}
|
||||
|
||||
IrCameraHandle camera_handle{
|
||||
.npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)),
|
||||
.npad_type = Core::HID::NpadStyleIndex::None,
|
||||
};
|
||||
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}",
|
||||
npad_id, camera_handle.npad_id, camera_handle.npad_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<u32>(device_handle);
|
||||
rb.PushRaw(camera_handle);
|
||||
}
|
||||
|
||||
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedPointingProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto mcu_version{rp.PopRaw<PackedMcuVersion>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
|
||||
mcu_version.minor);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
PackedFunctionLevel function_level;
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedImageTransferProcessorExConfig processor_config;
|
||||
u64 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem =
|
||||
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedIrLedProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
PackedFunctionLevel function_level;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
|
||||
parameters.function_level.function_level, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -17,6 +18,235 @@ public:
|
||||
~IRS() override;
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::IrCameraStatus
|
||||
enum IrCameraStatus : u32 {
|
||||
Available,
|
||||
Unsupported,
|
||||
Unconnected,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrCameraInternalStatus
|
||||
enum IrCameraInternalStatus : u32 {
|
||||
Stopped,
|
||||
FirmwareUpdateNeeded,
|
||||
Unkown2,
|
||||
Unkown3,
|
||||
Unkown4,
|
||||
FirmwareVersionRequested,
|
||||
FirmwareVersionIsInvalid,
|
||||
Ready,
|
||||
Setting,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::detail::StatusManager::IrSensorMode
|
||||
enum IrSensorMode : u64 {
|
||||
None,
|
||||
MomentProcessor,
|
||||
ClusteringProcessor,
|
||||
ImageTransferProcessor,
|
||||
PointingProcessorMarker,
|
||||
TeraPluginProcessor,
|
||||
IrLedProcessor,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::ImageProcessorStatus
|
||||
enum ImageProcessorStatus : u8 {
|
||||
stopped,
|
||||
running,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::ImageTransferProcessorFormat
|
||||
enum ImageTransferProcessorFormat : u8 {
|
||||
Size320x240,
|
||||
Size160x120,
|
||||
Size80x60,
|
||||
Size40x30,
|
||||
Size20x15,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::AdaptiveClusteringMode
|
||||
enum AdaptiveClusteringMode : u8 {
|
||||
StaticFov,
|
||||
DynamicFov,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::AdaptiveClusteringTargetDistance
|
||||
enum AdaptiveClusteringTargetDistance : u8 {
|
||||
Near,
|
||||
Middle,
|
||||
Far,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrsHandAnalysisMode
|
||||
enum IrsHandAnalysisMode : u8 {
|
||||
Silhouette,
|
||||
Image,
|
||||
SilhoueteAndImage,
|
||||
SilhuetteOnly,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrSensorFunctionLevel
|
||||
enum IrSensorFunctionLevel : u8 {
|
||||
unknown0,
|
||||
unknown1,
|
||||
unknown2,
|
||||
unknown3,
|
||||
unknown4,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrCameraHandle
|
||||
struct IrCameraHandle {
|
||||
u8 npad_id{};
|
||||
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size");
|
||||
|
||||
struct IrsRect {
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 width;
|
||||
s16 height;
|
||||
};
|
||||
|
||||
// This is nn::irsensor::PackedMcuVersion
|
||||
struct PackedMcuVersion {
|
||||
u16 major;
|
||||
u16 minor;
|
||||
};
|
||||
static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size");
|
||||
|
||||
// This is nn::irsensor::MomentProcessorConfig
|
||||
struct MomentProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
IrsRect window_of_interest;
|
||||
u8 preprocess;
|
||||
u8 preprocess_intensity_threshold;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
};
|
||||
static_assert(sizeof(MomentProcessorConfig) == 0x28,
|
||||
"MomentProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedMomentProcessorConfig
|
||||
struct PackedMomentProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 preprocess;
|
||||
u8 preprocess_intensity_threshold;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(PackedMomentProcessorConfig) == 0x20,
|
||||
"PackedMomentProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::ClusteringProcessorConfig
|
||||
struct ClusteringProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u32 light_target;
|
||||
u32 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
IrsRect window_of_interest;
|
||||
u32 pixel_count_min;
|
||||
u32 pixel_count_max;
|
||||
u32 object_intensity_min;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(ClusteringProcessorConfig) == 0x30,
|
||||
"ClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedClusteringProcessorConfig
|
||||
struct PackedClusteringProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u32 pixel_count_min;
|
||||
u32 pixel_count_max;
|
||||
u32 object_intensity_min;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30,
|
||||
"PackedClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedImageTransferProcessorConfig
|
||||
struct PackedImageTransferProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 format;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18,
|
||||
"PackedImageTransferProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedTeraPluginProcessorConfig
|
||||
struct PackedTeraPluginProcessorConfig {
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 mode;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8,
|
||||
"PackedTeraPluginProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedPointingProcessorConfig
|
||||
struct PackedPointingProcessorConfig {
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
};
|
||||
static_assert(sizeof(PackedPointingProcessorConfig) == 0xC,
|
||||
"PackedPointingProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedFunctionLevel
|
||||
struct PackedFunctionLevel {
|
||||
IrSensorFunctionLevel function_level;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedImageTransferProcessorExConfig
|
||||
struct PackedImageTransferProcessorExConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
PackedMcuVersion required_mcu_version;
|
||||
ImageTransferProcessorFormat origin_format;
|
||||
ImageTransferProcessorFormat trimming_format;
|
||||
u16 trimming_start_x;
|
||||
u16 trimming_start_y;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20,
|
||||
"PackedImageTransferProcessorExConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedIrLedProcessorConfig
|
||||
struct PackedIrLedProcessorConfig {
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 light_target;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8,
|
||||
"PackedIrLedProcessorConfig is an invalid size");
|
||||
|
||||
void ActivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx);
|
||||
@@ -35,8 +265,6 @@ private:
|
||||
void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
|
||||
void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
|
||||
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
|
||||
|
||||
const u32 device_handle{0xABCD};
|
||||
};
|
||||
|
||||
class IRS_SYS final : public ServiceFramework<IRS_SYS> {
|
||||
|
||||
@@ -11,10 +11,13 @@
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/div_ceil.h"
|
||||
#include "common/elf.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/jit/jit_context.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
using namespace Common::ELF;
|
||||
|
||||
namespace Service::JIT {
|
||||
|
||||
constexpr std::array<u8, 8> SVC0_ARM64 = {
|
||||
@@ -26,25 +29,6 @@ constexpr std::array HELPER_FUNCTIONS{
|
||||
"_stop", "_resolve", "_panic", "memcpy", "memmove", "memset",
|
||||
};
|
||||
|
||||
struct Elf64_Dyn {
|
||||
u64 d_tag;
|
||||
u64 d_un;
|
||||
};
|
||||
|
||||
struct Elf64_Rela {
|
||||
u64 r_offset;
|
||||
u64 r_info;
|
||||
s64 r_addend;
|
||||
};
|
||||
|
||||
static constexpr u32 Elf64_RelaType(const Elf64_Rela* rela) {
|
||||
return static_cast<u32>(rela->r_info);
|
||||
}
|
||||
|
||||
constexpr int DT_RELA = 7; /* Address of Rela relocs */
|
||||
constexpr int DT_RELASZ = 8; /* Total size of Rela relocs */
|
||||
constexpr int R_AARCH64_RELATIVE = 1027; /* Adjust by program base. */
|
||||
|
||||
constexpr size_t STACK_ALIGN = 16;
|
||||
|
||||
class JITContextImpl;
|
||||
@@ -206,17 +190,17 @@ public:
|
||||
if (!dyn.d_tag) {
|
||||
break;
|
||||
}
|
||||
if (dyn.d_tag == DT_RELA) {
|
||||
rela_dyn = dyn.d_un;
|
||||
if (dyn.d_tag == ElfDtRela) {
|
||||
rela_dyn = dyn.d_un.d_ptr;
|
||||
}
|
||||
if (dyn.d_tag == DT_RELASZ) {
|
||||
num_rela = dyn.d_un / sizeof(Elf64_Rela);
|
||||
if (dyn.d_tag == ElfDtRelasz) {
|
||||
num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_rela; i++) {
|
||||
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
|
||||
if (Elf64_RelaType(&rela) != R_AARCH64_RELATIVE) {
|
||||
if (Elf64RelType(rela.r_info) != ElfAArch64Relative) {
|
||||
continue;
|
||||
}
|
||||
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <memory>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/elf.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/code_set.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
@@ -13,159 +14,7 @@
|
||||
#include "core/loader/elf.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ELF Header Constants
|
||||
|
||||
// File type
|
||||
enum ElfType {
|
||||
ET_NONE = 0,
|
||||
ET_REL = 1,
|
||||
ET_EXEC = 2,
|
||||
ET_DYN = 3,
|
||||
ET_CORE = 4,
|
||||
ET_LOPROC = 0xFF00,
|
||||
ET_HIPROC = 0xFFFF,
|
||||
};
|
||||
|
||||
// Machine/Architecture
|
||||
enum ElfMachine {
|
||||
EM_NONE = 0,
|
||||
EM_M32 = 1,
|
||||
EM_SPARC = 2,
|
||||
EM_386 = 3,
|
||||
EM_68K = 4,
|
||||
EM_88K = 5,
|
||||
EM_860 = 7,
|
||||
EM_MIPS = 8
|
||||
};
|
||||
|
||||
// File version
|
||||
#define EV_NONE 0
|
||||
#define EV_CURRENT 1
|
||||
|
||||
// Identification index
|
||||
#define EI_MAG0 0
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
#define EI_PAD 7
|
||||
#define EI_NIDENT 16
|
||||
|
||||
// Sections constants
|
||||
|
||||
// Section types
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
#define SHT_LOPROC 0x70000000
|
||||
#define SHT_HIPROC 0x7FFFFFFF
|
||||
#define SHT_LOUSER 0x80000000
|
||||
#define SHT_HIUSER 0xFFFFFFFF
|
||||
|
||||
// Section flags
|
||||
enum ElfSectionFlags {
|
||||
SHF_WRITE = 0x1,
|
||||
SHF_ALLOC = 0x2,
|
||||
SHF_EXECINSTR = 0x4,
|
||||
SHF_MASKPROC = 0xF0000000,
|
||||
};
|
||||
|
||||
// Segment types
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define PT_NOTE 4
|
||||
#define PT_SHLIB 5
|
||||
#define PT_PHDR 6
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7FFFFFFF
|
||||
|
||||
// Segment flags
|
||||
#define PF_X 0x1
|
||||
#define PF_W 0x2
|
||||
#define PF_R 0x4
|
||||
#define PF_MASKPROC 0xF0000000
|
||||
|
||||
typedef unsigned int Elf32_Addr;
|
||||
typedef unsigned short Elf32_Half;
|
||||
typedef unsigned int Elf32_Off;
|
||||
typedef signed int Elf32_Sword;
|
||||
typedef unsigned int Elf32_Word;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ELF file header
|
||||
|
||||
struct Elf32_Ehdr {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
};
|
||||
|
||||
// Section header
|
||||
struct Elf32_Shdr {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
};
|
||||
|
||||
// Segment header
|
||||
struct Elf32_Phdr {
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
};
|
||||
|
||||
// Symbol table entry
|
||||
struct Elf32_Sym {
|
||||
Elf32_Word st_name;
|
||||
Elf32_Addr st_value;
|
||||
Elf32_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32_Half st_shndx;
|
||||
};
|
||||
|
||||
// Relocation entries
|
||||
struct Elf32_Rel {
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
};
|
||||
using namespace Common::ELF;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ElfReader class
|
||||
@@ -193,11 +42,11 @@ public:
|
||||
}
|
||||
|
||||
// Quick accessors
|
||||
ElfType GetType() const {
|
||||
return (ElfType)(header->e_type);
|
||||
u16 GetType() const {
|
||||
return header->e_type;
|
||||
}
|
||||
ElfMachine GetMachine() const {
|
||||
return (ElfMachine)(header->e_machine);
|
||||
u16 GetMachine() const {
|
||||
return header->e_machine;
|
||||
}
|
||||
VAddr GetEntryPoint() const {
|
||||
return entryPoint;
|
||||
@@ -220,13 +69,13 @@ public:
|
||||
const u8* GetSectionDataPtr(int section) const {
|
||||
if (section < 0 || section >= header->e_shnum)
|
||||
return nullptr;
|
||||
if (sections[section].sh_type != SHT_NOBITS)
|
||||
if (sections[section].sh_type != ElfShtNobits)
|
||||
return GetPtr(sections[section].sh_offset);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
bool IsCodeSection(int section) const {
|
||||
return sections[section].sh_type == SHT_PROGBITS;
|
||||
return sections[section].sh_type == ElfShtProgBits;
|
||||
}
|
||||
const u8* GetSegmentPtr(int segment) {
|
||||
return GetPtr(segments[segment].p_offset);
|
||||
@@ -256,7 +105,7 @@ ElfReader::ElfReader(void* ptr) {
|
||||
}
|
||||
|
||||
const char* ElfReader::GetSectionName(int section) const {
|
||||
if (sections[section].sh_type == SHT_NULL)
|
||||
if (sections[section].sh_type == ElfShtNull)
|
||||
return nullptr;
|
||||
|
||||
int name_offset = sections[section].sh_name;
|
||||
@@ -272,7 +121,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
|
||||
LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
|
||||
|
||||
// Should we relocate?
|
||||
relocate = (header->e_type != ET_EXEC);
|
||||
relocate = (header->e_type != ElfTypeExec);
|
||||
|
||||
if (relocate) {
|
||||
LOG_DEBUG(Loader, "Relocatable module");
|
||||
@@ -288,7 +137,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
|
||||
u64 total_image_size = 0;
|
||||
for (unsigned int i = 0; i < header->e_phnum; ++i) {
|
||||
const Elf32_Phdr* p = &segments[i];
|
||||
if (p->p_type == PT_LOAD) {
|
||||
if (p->p_type == ElfPtLoad) {
|
||||
total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
|
||||
}
|
||||
}
|
||||
@@ -303,14 +152,14 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
|
||||
LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
|
||||
p->p_vaddr, p->p_filesz, p->p_memsz);
|
||||
|
||||
if (p->p_type == PT_LOAD) {
|
||||
if (p->p_type == ElfPtLoad) {
|
||||
Kernel::CodeSet::Segment* codeset_segment;
|
||||
u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
|
||||
if (permission_flags == (PF_R | PF_X)) {
|
||||
u32 permission_flags = p->p_flags & (ElfPfRead | ElfPfWrite | ElfPfExec);
|
||||
if (permission_flags == (ElfPfRead | ElfPfExec)) {
|
||||
codeset_segment = &codeset.CodeSegment();
|
||||
} else if (permission_flags == (PF_R)) {
|
||||
} else if (permission_flags == (ElfPfRead)) {
|
||||
codeset_segment = &codeset.RODataSegment();
|
||||
} else if (permission_flags == (PF_R | PF_W)) {
|
||||
} else if (permission_flags == (ElfPfRead | ElfPfWrite)) {
|
||||
codeset_segment = &codeset.DataSegment();
|
||||
} else {
|
||||
LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,
|
||||
|
||||
@@ -595,8 +595,8 @@ void Maxwell3D::DrawArrays() {
|
||||
|
||||
std::optional<u64> Maxwell3D::GetQueryResult() {
|
||||
switch (regs.query.query_get.select) {
|
||||
case Regs::QuerySelect::Zero:
|
||||
return 0;
|
||||
case Regs::QuerySelect::Payload:
|
||||
return regs.query.query_sequence;
|
||||
case Regs::QuerySelect::SamplesPassed:
|
||||
// Deferred.
|
||||
rasterizer->Query(regs.query.QueryAddress(), QueryType::SamplesPassed,
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
};
|
||||
|
||||
enum class QuerySelect : u32 {
|
||||
Zero = 0,
|
||||
Payload = 0,
|
||||
TimeElapsed = 2,
|
||||
TransformFeedbackPrimitivesGenerated = 11,
|
||||
PrimitivesGenerated = 18,
|
||||
|
||||
@@ -198,6 +198,31 @@ static void RemoveCachedContents() {
|
||||
Common::FS::RemoveDirRecursively(offline_system_data);
|
||||
}
|
||||
|
||||
static QString PrettyProductName() {
|
||||
#ifdef _WIN32
|
||||
// After Windows 10 Version 2004, Microsoft decided to switch to a different notation: 20H2
|
||||
// With that notation change they changed the registry key used to denote the current version
|
||||
QSettings windows_registry(
|
||||
QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
|
||||
QSettings::NativeFormat);
|
||||
const QString release_id = windows_registry.value(QStringLiteral("ReleaseId")).toString();
|
||||
if (release_id == QStringLiteral("2009")) {
|
||||
const u32 current_build = windows_registry.value(QStringLiteral("CurrentBuild")).toUInt();
|
||||
const QString display_version =
|
||||
windows_registry.value(QStringLiteral("DisplayVersion")).toString();
|
||||
const u32 ubr = windows_registry.value(QStringLiteral("UBR")).toUInt();
|
||||
u32 version = 10;
|
||||
if (current_build >= 22000) {
|
||||
version = 11;
|
||||
}
|
||||
return QStringLiteral("Windows %1 Version %2 (Build %3.%4)")
|
||||
.arg(QString::number(version), display_version, QString::number(current_build),
|
||||
QString::number(ubr));
|
||||
}
|
||||
#endif
|
||||
return QSysInfo::prettyProductName();
|
||||
}
|
||||
|
||||
GMainWindow::GMainWindow()
|
||||
: ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
|
||||
input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
|
||||
@@ -259,7 +284,7 @@ GMainWindow::GMainWindow()
|
||||
}
|
||||
LOG_INFO(Frontend, "Host CPU: {}", cpu_string);
|
||||
#endif
|
||||
LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString());
|
||||
LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString());
|
||||
LOG_INFO(Frontend, "Host RAM: {:.2f} GiB",
|
||||
Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB});
|
||||
LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB});
|
||||
@@ -1015,6 +1040,10 @@ void GMainWindow::SetDefaultUIGeometry() {
|
||||
void GMainWindow::RestoreUIState() {
|
||||
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
|
||||
restoreGeometry(UISettings::values.geometry);
|
||||
// Work-around because the games list isn't supposed to be full screen
|
||||
if (isFullScreen()) {
|
||||
showNormal();
|
||||
}
|
||||
restoreState(UISettings::values.state);
|
||||
render_window->setWindowFlags(render_window->windowFlags() & ~Qt::FramelessWindowHint);
|
||||
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
||||
|
||||
Reference in New Issue
Block a user