Sources: Run clang-format on everything.
This commit is contained in:
parent
fe948af095
commit
dc8479928c
386 changed files with 19560 additions and 18080 deletions
|
@ -9,7 +9,7 @@
|
|||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||
|
||||
namespace Core {
|
||||
struct ThreadContext;
|
||||
struct ThreadContext;
|
||||
}
|
||||
|
||||
/// Generic ARM11 CPU interface
|
||||
|
@ -141,10 +141,10 @@ public:
|
|||
return num_instructions;
|
||||
}
|
||||
|
||||
s64 down_count = 0; ///< A decreasing counter of remaining cycles before the next event, decreased by the cpu run loop
|
||||
s64 down_count = 0; ///< A decreasing counter of remaining cycles before the next event,
|
||||
/// decreased by the cpu run loop
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Executes the given number of instructions
|
||||
* @param num_instructions Number of instructions to executes
|
||||
|
@ -152,6 +152,5 @@ protected:
|
|||
virtual void ExecuteInstructions(int num_instructions) = 0;
|
||||
|
||||
private:
|
||||
|
||||
u64 num_instructions = 0; ///< Number of instructions executed
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -187,53 +187,53 @@ enum Opcode {
|
|||
OP_THUMB_SWI,
|
||||
OP_THUMB_TST,
|
||||
|
||||
OP_END // must be last
|
||||
OP_END // must be last
|
||||
};
|
||||
|
||||
class ARM_Disasm {
|
||||
public:
|
||||
static std::string Disassemble(u32 addr, u32 insn);
|
||||
static Opcode Decode(u32 insn);
|
||||
public:
|
||||
static std::string Disassemble(u32 addr, u32 insn);
|
||||
static Opcode Decode(u32 insn);
|
||||
|
||||
private:
|
||||
static Opcode Decode00(u32 insn);
|
||||
static Opcode Decode01(u32 insn);
|
||||
static Opcode Decode10(u32 insn);
|
||||
static Opcode Decode11(u32 insn);
|
||||
static Opcode DecodeSyncPrimitive(u32 insn);
|
||||
static Opcode DecodeParallelAddSub(u32 insn);
|
||||
static Opcode DecodePackingSaturationReversal(u32 insn);
|
||||
static Opcode DecodeMUL(u32 insn);
|
||||
static Opcode DecodeMSRImmAndHints(u32 insn);
|
||||
static Opcode DecodeMediaMulDiv(u32 insn);
|
||||
static Opcode DecodeMedia(u32 insn);
|
||||
static Opcode DecodeLDRH(u32 insn);
|
||||
static Opcode DecodeALU(u32 insn);
|
||||
private:
|
||||
static Opcode Decode00(u32 insn);
|
||||
static Opcode Decode01(u32 insn);
|
||||
static Opcode Decode10(u32 insn);
|
||||
static Opcode Decode11(u32 insn);
|
||||
static Opcode DecodeSyncPrimitive(u32 insn);
|
||||
static Opcode DecodeParallelAddSub(u32 insn);
|
||||
static Opcode DecodePackingSaturationReversal(u32 insn);
|
||||
static Opcode DecodeMUL(u32 insn);
|
||||
static Opcode DecodeMSRImmAndHints(u32 insn);
|
||||
static Opcode DecodeMediaMulDiv(u32 insn);
|
||||
static Opcode DecodeMedia(u32 insn);
|
||||
static Opcode DecodeLDRH(u32 insn);
|
||||
static Opcode DecodeALU(u32 insn);
|
||||
|
||||
static std::string DisassembleALU(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleBranch(u32 addr, Opcode opcode, u32 insn);
|
||||
static std::string DisassembleBX(u32 insn);
|
||||
static std::string DisassembleBKPT(u32 insn);
|
||||
static std::string DisassembleCLZ(u32 insn);
|
||||
static std::string DisassembleMediaMulDiv(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMemblock(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMem(u32 insn);
|
||||
static std::string DisassembleMemHalf(u32 insn);
|
||||
static std::string DisassembleMCR(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMLA(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleUMLAL(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMUL(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMRS(u32 insn);
|
||||
static std::string DisassembleMSR(u32 insn);
|
||||
static std::string DisassembleNoOperands(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleParallelAddSub(Opcode opcode, u32 insn);
|
||||
static std::string DisassemblePKH(u32 insn);
|
||||
static std::string DisassemblePLD(u32 insn);
|
||||
static std::string DisassembleREV(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleREX(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleSAT(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleSEL(u32 insn);
|
||||
static std::string DisassembleSWI(u32 insn);
|
||||
static std::string DisassembleSWP(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleXT(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleALU(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleBranch(u32 addr, Opcode opcode, u32 insn);
|
||||
static std::string DisassembleBX(u32 insn);
|
||||
static std::string DisassembleBKPT(u32 insn);
|
||||
static std::string DisassembleCLZ(u32 insn);
|
||||
static std::string DisassembleMediaMulDiv(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMemblock(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMem(u32 insn);
|
||||
static std::string DisassembleMemHalf(u32 insn);
|
||||
static std::string DisassembleMCR(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMLA(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleUMLAL(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMUL(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleMRS(u32 insn);
|
||||
static std::string DisassembleMSR(u32 insn);
|
||||
static std::string DisassembleNoOperands(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleParallelAddSub(Opcode opcode, u32 insn);
|
||||
static std::string DisassemblePKH(u32 insn);
|
||||
static std::string DisassemblePLD(u32 insn);
|
||||
static std::string DisassembleREV(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleREX(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleSAT(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleSEL(u32 insn);
|
||||
static std::string DisassembleSWI(u32 insn);
|
||||
static std::string DisassembleSWP(Opcode opcode, u32 insn);
|
||||
static std::string DisassembleXT(Opcode opcode, u32 insn);
|
||||
};
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/symbols.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/symbols.h"
|
||||
|
||||
#include "core/arm/disassembler/load_symbol_map.h"
|
||||
|
||||
|
|
|
@ -430,12 +430,15 @@ ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) {
|
|||
continue;
|
||||
|
||||
while (n) {
|
||||
if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
|
||||
if (arm_instruction[i].content[base + 1] == 31 &&
|
||||
arm_instruction[i].content[base] == 0) {
|
||||
// clrex
|
||||
if (instr != arm_instruction[i].content[base + 2]) {
|
||||
break;
|
||||
}
|
||||
} else if (BITS(instr, arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) {
|
||||
} else if (BITS(instr, arm_instruction[i].content[base],
|
||||
arm_instruction[i].content[base + 1]) !=
|
||||
arm_instruction[i].content[base + 2]) {
|
||||
break;
|
||||
}
|
||||
base += 3;
|
||||
|
@ -451,7 +454,9 @@ ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) {
|
|||
if (n != 0) {
|
||||
base = 0;
|
||||
while (n) {
|
||||
if (BITS(instr, arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) {
|
||||
if (BITS(instr, arm_exclusion_code[i].content[base],
|
||||
arm_exclusion_code[i].content[base + 1]) !=
|
||||
arm_exclusion_code[i].content[base + 2]) {
|
||||
break;
|
||||
}
|
||||
base += 3;
|
||||
|
|
|
@ -6,15 +6,12 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
|
||||
enum class ARMDecodeStatus {
|
||||
SUCCESS,
|
||||
FAILURE
|
||||
};
|
||||
enum class ARMDecodeStatus { SUCCESS, FAILURE };
|
||||
|
||||
ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx);
|
||||
|
||||
struct InstructionSetEncodingItem {
|
||||
const char *name;
|
||||
const char* name;
|
||||
int attribute_value;
|
||||
int version;
|
||||
u32 content[21];
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,50 +21,48 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
*ainstr = 0xDEADC0DE; // Debugging to catch non updates
|
||||
|
||||
switch ((tinstr & 0xF800) >> 11) {
|
||||
case 0: // LSL
|
||||
case 1: // LSR
|
||||
case 2: // ASR
|
||||
*ainstr = 0xE1B00000 // base opcode
|
||||
| ((tinstr & 0x1800) >> (11 - 5)) // shift type
|
||||
|((tinstr & 0x07C0) << (7 - 6)) // imm5
|
||||
|((tinstr & 0x0038) >> 3) // Rs
|
||||
|((tinstr & 0x0007) << 12); // Rd
|
||||
case 0: // LSL
|
||||
case 1: // LSR
|
||||
case 2: // ASR
|
||||
*ainstr = 0xE1B00000 // base opcode
|
||||
| ((tinstr & 0x1800) >> (11 - 5)) // shift type
|
||||
| ((tinstr & 0x07C0) << (7 - 6)) // imm5
|
||||
| ((tinstr & 0x0038) >> 3) // Rs
|
||||
| ((tinstr & 0x0007) << 12); // Rd
|
||||
break;
|
||||
|
||||
case 3: // ADD/SUB
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE0900000, // ADDS Rd,Rs,Rn
|
||||
0xE0500000, // SUBS Rd,Rs,Rn
|
||||
0xE2900000, // ADDS Rd,Rs,#imm3
|
||||
0xE2500000 // SUBS Rd,Rs,#imm3
|
||||
};
|
||||
// It is quicker indexing into a table, than performing switch or conditionals:
|
||||
*ainstr = subset[(tinstr & 0x0600) >> 9] // base opcode
|
||||
|((tinstr & 0x01C0) >> 6) // Rn or imm3
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rs
|
||||
|((tinstr & 0x0007) << (12 - 0)); // Rd
|
||||
}
|
||||
break;
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE0900000, // ADDS Rd,Rs,Rn
|
||||
0xE0500000, // SUBS Rd,Rs,Rn
|
||||
0xE2900000, // ADDS Rd,Rs,#imm3
|
||||
0xE2500000 // SUBS Rd,Rs,#imm3
|
||||
};
|
||||
// It is quicker indexing into a table, than performing switch or conditionals:
|
||||
*ainstr = subset[(tinstr & 0x0600) >> 9] // base opcode
|
||||
| ((tinstr & 0x01C0) >> 6) // Rn or imm3
|
||||
| ((tinstr & 0x0038) << (16 - 3)) // Rs
|
||||
| ((tinstr & 0x0007) << (12 - 0)); // Rd
|
||||
} break;
|
||||
|
||||
case 4: // MOV
|
||||
case 5: // CMP
|
||||
case 6: // ADD
|
||||
case 7: // SUB
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE3B00000, // MOVS Rd,#imm8
|
||||
0xE3500000, // CMP Rd,#imm8
|
||||
0xE2900000, // ADDS Rd,Rd,#imm8
|
||||
0xE2500000, // SUBS Rd,Rd,#imm8
|
||||
};
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE3B00000, // MOVS Rd,#imm8
|
||||
0xE3500000, // CMP Rd,#imm8
|
||||
0xE2900000, // ADDS Rd,Rd,#imm8
|
||||
0xE2500000, // SUBS Rd,Rd,#imm8
|
||||
};
|
||||
|
||||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base opcode
|
||||
|((tinstr & 0x00FF) >> 0) // imm8
|
||||
|((tinstr & 0x0700) << (16 - 8)) // Rn
|
||||
|((tinstr & 0x0700) << (12 - 8)); // Rd
|
||||
}
|
||||
break;
|
||||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base opcode
|
||||
| ((tinstr & 0x00FF) >> 0) // imm8
|
||||
| ((tinstr & 0x0700) << (16 - 8)) // Rn
|
||||
| ((tinstr & 0x0700) << (12 - 8)); // Rd
|
||||
} break;
|
||||
|
||||
case 8: // Arithmetic and high register transfers
|
||||
|
||||
|
@ -73,56 +71,51 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
// large subset
|
||||
|
||||
if ((tinstr & (1 << 10)) == 0) {
|
||||
enum otype {
|
||||
t_norm,
|
||||
t_shift,
|
||||
t_neg,
|
||||
t_mul
|
||||
};
|
||||
enum otype { t_norm, t_shift, t_neg, t_mul };
|
||||
|
||||
static const struct {
|
||||
u32 opcode;
|
||||
otype type;
|
||||
} subset[16] = {
|
||||
{ 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs
|
||||
{ 0xE0300000, t_norm }, // EORS Rd,Rd,Rs
|
||||
{ 0xE1B00010, t_shift }, // MOVS Rd,Rd,LSL Rs
|
||||
{ 0xE1B00030, t_shift }, // MOVS Rd,Rd,LSR Rs
|
||||
{ 0xE1B00050, t_shift }, // MOVS Rd,Rd,ASR Rs
|
||||
{ 0xE0B00000, t_norm }, // ADCS Rd,Rd,Rs
|
||||
{ 0xE0D00000, t_norm }, // SBCS Rd,Rd,Rs
|
||||
{ 0xE1B00070, t_shift }, // MOVS Rd,Rd,ROR Rs
|
||||
{ 0xE1100000, t_norm }, // TST Rd,Rs
|
||||
{ 0xE2700000, t_neg }, // RSBS Rd,Rs,#0
|
||||
{ 0xE1500000, t_norm }, // CMP Rd,Rs
|
||||
{ 0xE1700000, t_norm }, // CMN Rd,Rs
|
||||
{ 0xE1900000, t_norm }, // ORRS Rd,Rd,Rs
|
||||
{ 0xE0100090, t_mul }, // MULS Rd,Rd,Rs
|
||||
{ 0xE1D00000, t_norm }, // BICS Rd,Rd,Rs
|
||||
{ 0xE1F00000, t_norm } // MVNS Rd,Rs
|
||||
{0xE0100000, t_norm}, // ANDS Rd,Rd,Rs
|
||||
{0xE0300000, t_norm}, // EORS Rd,Rd,Rs
|
||||
{0xE1B00010, t_shift}, // MOVS Rd,Rd,LSL Rs
|
||||
{0xE1B00030, t_shift}, // MOVS Rd,Rd,LSR Rs
|
||||
{0xE1B00050, t_shift}, // MOVS Rd,Rd,ASR Rs
|
||||
{0xE0B00000, t_norm}, // ADCS Rd,Rd,Rs
|
||||
{0xE0D00000, t_norm}, // SBCS Rd,Rd,Rs
|
||||
{0xE1B00070, t_shift}, // MOVS Rd,Rd,ROR Rs
|
||||
{0xE1100000, t_norm}, // TST Rd,Rs
|
||||
{0xE2700000, t_neg}, // RSBS Rd,Rs,#0
|
||||
{0xE1500000, t_norm}, // CMP Rd,Rs
|
||||
{0xE1700000, t_norm}, // CMN Rd,Rs
|
||||
{0xE1900000, t_norm}, // ORRS Rd,Rd,Rs
|
||||
{0xE0100090, t_mul}, // MULS Rd,Rd,Rs
|
||||
{0xE1D00000, t_norm}, // BICS Rd,Rd,Rs
|
||||
{0xE1F00000, t_norm} // MVNS Rd,Rs
|
||||
};
|
||||
|
||||
*ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; // base
|
||||
|
||||
switch (subset[(tinstr & 0x03C0) >> 6].type) {
|
||||
case t_norm:
|
||||
*ainstr |= ((tinstr & 0x0007) << 16) // Rn
|
||||
|((tinstr & 0x0007) << 12) // Rd
|
||||
|((tinstr & 0x0038) >> 3); // Rs
|
||||
*ainstr |= ((tinstr & 0x0007) << 16) // Rn
|
||||
| ((tinstr & 0x0007) << 12) // Rd
|
||||
| ((tinstr & 0x0038) >> 3); // Rs
|
||||
break;
|
||||
case t_shift:
|
||||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
||||
|((tinstr & 0x0007) >> 0) // Rm
|
||||
|((tinstr & 0x0038) << (8 - 3)); // Rs
|
||||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
||||
| ((tinstr & 0x0007) >> 0) // Rm
|
||||
| ((tinstr & 0x0038) << (8 - 3)); // Rs
|
||||
break;
|
||||
case t_neg:
|
||||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)); // Rn
|
||||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
||||
| ((tinstr & 0x0038) << (16 - 3)); // Rn
|
||||
break;
|
||||
case t_mul:
|
||||
*ainstr |= ((tinstr & 0x0007) << 16) // Rd
|
||||
|((tinstr & 0x0007) << 8) // Rs
|
||||
|((tinstr & 0x0038) >> 3); // Rm
|
||||
*ainstr |= ((tinstr & 0x0007) << 16) // Rd
|
||||
| ((tinstr & 0x0007) << 8) // Rs
|
||||
| ((tinstr & 0x0038) >> 3); // Rm
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -133,109 +126,106 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
Rd += 8;
|
||||
|
||||
switch ((tinstr & 0x03C0) >> 6) {
|
||||
case 0x0: // ADD Rd,Rd,Rs
|
||||
case 0x1: // ADD Rd,Rd,Hs
|
||||
case 0x2: // ADD Hd,Hd,Rs
|
||||
case 0x3: // ADD Hd,Hd,Hs
|
||||
*ainstr = 0xE0800000 // base
|
||||
| (Rd << 16) // Rn
|
||||
|(Rd << 12) // Rd
|
||||
|(Rs << 0); // Rm
|
||||
case 0x0: // ADD Rd,Rd,Rs
|
||||
case 0x1: // ADD Rd,Rd,Hs
|
||||
case 0x2: // ADD Hd,Hd,Rs
|
||||
case 0x3: // ADD Hd,Hd,Hs
|
||||
*ainstr = 0xE0800000 // base
|
||||
| (Rd << 16) // Rn
|
||||
| (Rd << 12) // Rd
|
||||
| (Rs << 0); // Rm
|
||||
break;
|
||||
case 0x4: // CMP Rd,Rs
|
||||
case 0x5: // CMP Rd,Hs
|
||||
case 0x6: // CMP Hd,Rs
|
||||
case 0x7: // CMP Hd,Hs
|
||||
*ainstr = 0xE1500000 // base
|
||||
| (Rd << 16) // Rn
|
||||
|(Rs << 0); // Rm
|
||||
case 0x4: // CMP Rd,Rs
|
||||
case 0x5: // CMP Rd,Hs
|
||||
case 0x6: // CMP Hd,Rs
|
||||
case 0x7: // CMP Hd,Hs
|
||||
*ainstr = 0xE1500000 // base
|
||||
| (Rd << 16) // Rn
|
||||
| (Rs << 0); // Rm
|
||||
break;
|
||||
case 0x8: // MOV Rd,Rs
|
||||
case 0x9: // MOV Rd,Hs
|
||||
case 0xA: // MOV Hd,Rs
|
||||
case 0xB: // MOV Hd,Hs
|
||||
*ainstr = 0xE1A00000 // base
|
||||
|(Rd << 12) // Rd
|
||||
|(Rs << 0); // Rm
|
||||
case 0x8: // MOV Rd,Rs
|
||||
case 0x9: // MOV Rd,Hs
|
||||
case 0xA: // MOV Hd,Rs
|
||||
case 0xB: // MOV Hd,Hs
|
||||
*ainstr = 0xE1A00000 // base
|
||||
| (Rd << 12) // Rd
|
||||
| (Rs << 0); // Rm
|
||||
break;
|
||||
case 0xC: // BX Rs
|
||||
case 0xD: // BX Hs
|
||||
*ainstr = 0xE12FFF10 // base
|
||||
| ((tinstr & 0x0078) >> 3); // Rd
|
||||
case 0xC: // BX Rs
|
||||
case 0xD: // BX Hs
|
||||
*ainstr = 0xE12FFF10 // base
|
||||
| ((tinstr & 0x0078) >> 3); // Rd
|
||||
break;
|
||||
case 0xE: // BLX
|
||||
case 0xF: // BLX
|
||||
*ainstr = 0xE1200030 // base
|
||||
| (Rs << 0); // Rm
|
||||
case 0xE: // BLX
|
||||
case 0xF: // BLX
|
||||
*ainstr = 0xE1200030 // base
|
||||
| (Rs << 0); // Rm
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: // LDR Rd,[PC,#imm8]
|
||||
*ainstr = 0xE59F0000 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|((tinstr & 0x00FF) << (2 - 0)); // off8
|
||||
case 9: // LDR Rd,[PC,#imm8]
|
||||
*ainstr = 0xE59F0000 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
| ((tinstr & 0x00FF) << (2 - 0)); // off8
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case 11:
|
||||
{
|
||||
static const u32 subset[8] = {
|
||||
0xE7800000, // STR Rd,[Rb,Ro]
|
||||
0xE18000B0, // STRH Rd,[Rb,Ro]
|
||||
0xE7C00000, // STRB Rd,[Rb,Ro]
|
||||
0xE19000D0, // LDRSB Rd,[Rb,Ro]
|
||||
0xE7900000, // LDR Rd,[Rb,Ro]
|
||||
0xE19000B0, // LDRH Rd,[Rb,Ro]
|
||||
0xE7D00000, // LDRB Rd,[Rb,Ro]
|
||||
0xE19000F0 // LDRSH Rd,[Rb,Ro]
|
||||
};
|
||||
case 11: {
|
||||
static const u32 subset[8] = {
|
||||
0xE7800000, // STR Rd,[Rb,Ro]
|
||||
0xE18000B0, // STRH Rd,[Rb,Ro]
|
||||
0xE7C00000, // STRB Rd,[Rb,Ro]
|
||||
0xE19000D0, // LDRSB Rd,[Rb,Ro]
|
||||
0xE7900000, // LDR Rd,[Rb,Ro]
|
||||
0xE19000B0, // LDRH Rd,[Rb,Ro]
|
||||
0xE7D00000, // LDRB Rd,[Rb,Ro]
|
||||
0xE19000F0 // LDRSH Rd,[Rb,Ro]
|
||||
};
|
||||
|
||||
*ainstr = subset[(tinstr & 0xE00) >> 9] // base
|
||||
|((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
|((tinstr & 0x01C0) >> 6); // Ro
|
||||
}
|
||||
break;
|
||||
*ainstr = subset[(tinstr & 0xE00) >> 9] // base
|
||||
| ((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
| ((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
| ((tinstr & 0x01C0) >> 6); // Ro
|
||||
} break;
|
||||
|
||||
case 12: // STR Rd,[Rb,#imm5]
|
||||
case 13: // LDR Rd,[Rb,#imm5]
|
||||
case 14: // STRB Rd,[Rb,#imm5]
|
||||
case 15: // LDRB Rd,[Rb,#imm5]
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE5800000, // STR Rd,[Rb,#imm5]
|
||||
0xE5900000, // LDR Rd,[Rb,#imm5]
|
||||
0xE5C00000, // STRB Rd,[Rb,#imm5]
|
||||
0xE5D00000 // LDRB Rd,[Rb,#imm5]
|
||||
};
|
||||
// The offset range defends on whether we are transferring a byte or word value:
|
||||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base
|
||||
|((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
|((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); // off5
|
||||
}
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE5800000, // STR Rd,[Rb,#imm5]
|
||||
0xE5900000, // LDR Rd,[Rb,#imm5]
|
||||
0xE5C00000, // STRB Rd,[Rb,#imm5]
|
||||
0xE5D00000 // LDRB Rd,[Rb,#imm5]
|
||||
};
|
||||
// The offset range defends on whether we are transferring a byte or word value:
|
||||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base
|
||||
| ((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
| ((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
| ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); // off5
|
||||
} break;
|
||||
|
||||
case 16: // STRH Rd,[Rb,#imm5]
|
||||
case 17: // LDRH Rd,[Rb,#imm5]
|
||||
*ainstr = ((tinstr & (1 << 11)) // base
|
||||
? 0xE1D000B0 // LDRH
|
||||
: 0xE1C000B0) // STRH
|
||||
| ((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
| ((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
| ((tinstr & 0x01C0) >> (6 - 1)) // off5, low nibble
|
||||
| ((tinstr & 0x0600) >> (9 - 8)); // off5, high nibble
|
||||
break;
|
||||
|
||||
case 16: // STRH Rd,[Rb,#imm5]
|
||||
case 17: // LDRH Rd,[Rb,#imm5]
|
||||
*ainstr = ((tinstr & (1 << 11)) // base
|
||||
? 0xE1D000B0 // LDRH
|
||||
: 0xE1C000B0) // STRH
|
||||
|((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
|((tinstr & 0x01C0) >> (6 - 1)) // off5, low nibble
|
||||
|((tinstr & 0x0600) >> (9 - 8)); // off5, high nibble
|
||||
break;
|
||||
|
||||
case 18: // STR Rd,[SP,#imm8]
|
||||
case 19: // LDR Rd,[SP,#imm8]
|
||||
*ainstr = ((tinstr & (1 << 11)) // base
|
||||
? 0xE59D0000 // LDR
|
||||
: 0xE58D0000) // STR
|
||||
|((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|((tinstr & 0x00FF) << 2); // off8
|
||||
case 18: // STR Rd,[SP,#imm8]
|
||||
case 19: // LDR Rd,[SP,#imm8]
|
||||
*ainstr = ((tinstr & (1 << 11)) // base
|
||||
? 0xE59D0000 // LDR
|
||||
: 0xE58D0000) // STR
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
| ((tinstr & 0x00FF) << 2); // off8
|
||||
break;
|
||||
|
||||
case 20: // ADD Rd,PC,#imm8
|
||||
|
@ -246,14 +236,15 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
// NOTE: The PC value used here should by word aligned. We encode shift-left-by-2 in the
|
||||
// rotate immediate field, so no shift of off8 is needed.
|
||||
|
||||
*ainstr = 0xE28F0F00 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|(tinstr & 0x00FF); // off8
|
||||
*ainstr = 0xE28F0F00 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
| (tinstr & 0x00FF); // off8
|
||||
} else {
|
||||
// We encode shift-left-by-2 in the rotate immediate field, so no shift of off8 is needed.
|
||||
*ainstr = 0xE28D0F00 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|(tinstr & 0x00FF); // off8
|
||||
// We encode shift-left-by-2 in the rotate immediate field, so no shift of off8 is
|
||||
// needed.
|
||||
*ainstr = 0xE28D0F00 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
| (tinstr & 0x00FF); // off8
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -261,15 +252,15 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
case 23:
|
||||
if ((tinstr & 0x0F00) == 0x0000) {
|
||||
// NOTE: The instruction contains a shift left of 2 equivalent (implemented as ROR #30):
|
||||
*ainstr = ((tinstr & (1 << 7)) // base
|
||||
? 0xE24DDF00 // SUB
|
||||
: 0xE28DDF00) // ADD
|
||||
|(tinstr & 0x007F); // off7
|
||||
*ainstr = ((tinstr & (1 << 7)) // base
|
||||
? 0xE24DDF00 // SUB
|
||||
: 0xE28DDF00) // ADD
|
||||
| (tinstr & 0x007F); // off7
|
||||
} else if ((tinstr & 0x0F00) == 0x0e00) {
|
||||
// BKPT
|
||||
*ainstr = 0xEF000000 // base
|
||||
| BITS(tinstr, 0, 3) // imm4 field;
|
||||
| (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
|
||||
*ainstr = 0xEF000000 // base
|
||||
| BITS(tinstr, 0, 3) // imm4 field;
|
||||
| (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
|
||||
} else if ((tinstr & 0x0F00) == 0x0200) {
|
||||
static const u32 subset[4] = {
|
||||
0xE6BF0070, // SXTH
|
||||
|
@ -278,21 +269,21 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
0xE6EF0070, // UXTB
|
||||
};
|
||||
|
||||
*ainstr = subset[BITS(tinstr, 6, 7)] // base
|
||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||
| BITS(tinstr, 3, 5); // Rm
|
||||
*ainstr = subset[BITS(tinstr, 6, 7)] // base
|
||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||
| BITS(tinstr, 3, 5); // Rm
|
||||
} else if ((tinstr & 0x0F00) == 0x600) {
|
||||
if (BIT(tinstr, 5) == 0) {
|
||||
// SETEND
|
||||
*ainstr = 0xF1010000 // base
|
||||
| (BIT(tinstr, 3) << 9); // endian specifier
|
||||
*ainstr = 0xF1010000 // base
|
||||
| (BIT(tinstr, 3) << 9); // endian specifier
|
||||
} else {
|
||||
// CPS
|
||||
*ainstr = 0xF1080000 // base
|
||||
| (BIT(tinstr, 0) << 6) // fiq bit
|
||||
| (BIT(tinstr, 1) << 7) // irq bit
|
||||
| (BIT(tinstr, 2) << 8) // abort bit
|
||||
| (BIT(tinstr, 4) << 18); // enable bit
|
||||
*ainstr = 0xF1080000 // base
|
||||
| (BIT(tinstr, 0) << 6) // fiq bit
|
||||
| (BIT(tinstr, 1) << 7) // irq bit
|
||||
| (BIT(tinstr, 2) << 8) // abort bit
|
||||
| (BIT(tinstr, 4) << 18); // enable bit
|
||||
}
|
||||
} else if ((tinstr & 0x0F00) == 0x0a00) {
|
||||
static const u32 subset[4] = {
|
||||
|
@ -307,9 +298,9 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
if (subset_index == 2) {
|
||||
valid = ThumbDecodeStatus::UNDEFINED;
|
||||
} else {
|
||||
*ainstr = subset[subset_index] // base
|
||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||
| BITS(tinstr, 3, 5); // Rm
|
||||
*ainstr = subset[subset_index] // base
|
||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||
| BITS(tinstr, 3, 5); // Rm
|
||||
}
|
||||
} else {
|
||||
static const u32 subset[4] = {
|
||||
|
@ -319,14 +310,13 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
0xE8BD8000 // LDMIA sp!,{rlist,pc}
|
||||
};
|
||||
*ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] // base
|
||||
|(tinstr & 0x00FF); // mask8
|
||||
| (tinstr & 0x00FF); // mask8
|
||||
}
|
||||
break;
|
||||
|
||||
case 24: // STMIA
|
||||
case 25: // LDMIA
|
||||
if (tinstr & (1 << 11))
|
||||
{
|
||||
if (tinstr & (1 << 11)) {
|
||||
unsigned int base = 0xE8900000;
|
||||
unsigned int rn = BITS(tinstr, 8, 10);
|
||||
|
||||
|
@ -334,15 +324,13 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
|
|||
if ((tinstr & (1 << rn)) == 0)
|
||||
base |= (1 << 21);
|
||||
|
||||
*ainstr = base // base (LDMIA)
|
||||
| (rn << 16) // Rn
|
||||
| (tinstr & 0x00FF); // Register list
|
||||
}
|
||||
else
|
||||
{
|
||||
*ainstr = 0xE8A00000 // base (STMIA)
|
||||
| (BITS(tinstr, 8, 10) << 16) // Rn
|
||||
| (tinstr & 0x00FF); // Register list
|
||||
*ainstr = base // base (LDMIA)
|
||||
| (rn << 16) // Rn
|
||||
| (tinstr & 0x00FF); // Register list
|
||||
} else {
|
||||
*ainstr = 0xE8A00000 // base (STMIA)
|
||||
| (BITS(tinstr, 8, 10) << 16) // Rn
|
||||
| (tinstr & 0x00FF); // Register list
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
#include "common/common_types.h"
|
||||
|
||||
enum class ThumbDecodeStatus {
|
||||
UNDEFINED, // Undefined Thumb instruction
|
||||
DECODED, // Instruction decoded to ARM equivalent
|
||||
BRANCH, // Thumb branch (already processed)
|
||||
UNDEFINED, // Undefined Thumb instruction
|
||||
DECODED, // Instruction decoded to ARM equivalent
|
||||
BRANCH, // Thumb branch (already processed)
|
||||
UNINITIALIZED,
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,15 +2,15 @@ struct ARMul_State;
|
|||
typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
|
||||
|
||||
enum class TransExtData {
|
||||
COND = (1 << 0),
|
||||
NON_BRANCH = (1 << 1),
|
||||
DIRECT_BRANCH = (1 << 2),
|
||||
COND = (1 << 0),
|
||||
NON_BRANCH = (1 << 1),
|
||||
DIRECT_BRANCH = (1 << 2),
|
||||
INDIRECT_BRANCH = (1 << 3),
|
||||
CALL = (1 << 4),
|
||||
RET = (1 << 5),
|
||||
END_OF_PAGE = (1 << 6),
|
||||
THUMB = (1 << 7),
|
||||
SINGLE_STEP = (1 << 8)
|
||||
CALL = (1 << 4),
|
||||
RET = (1 << 5),
|
||||
END_OF_PAGE = (1 << 6),
|
||||
THUMB = (1 << 7),
|
||||
SINGLE_STEP = (1 << 8)
|
||||
};
|
||||
|
||||
struct arm_inst {
|
||||
|
@ -106,8 +106,7 @@ struct cps_inst {
|
|||
unsigned int mode;
|
||||
};
|
||||
|
||||
struct clrex_inst {
|
||||
};
|
||||
struct clrex_inst {};
|
||||
|
||||
struct cpy_inst {
|
||||
unsigned int Rm;
|
||||
|
@ -163,11 +162,9 @@ struct bkpt_inst {
|
|||
u32 imm;
|
||||
};
|
||||
|
||||
struct stc_inst {
|
||||
};
|
||||
struct stc_inst {};
|
||||
|
||||
struct ldc_inst {
|
||||
};
|
||||
struct ldc_inst {};
|
||||
|
||||
struct swi_inst {
|
||||
unsigned int num;
|
||||
|
@ -369,8 +366,7 @@ struct msr_inst {
|
|||
unsigned int inst;
|
||||
};
|
||||
|
||||
struct pld_inst {
|
||||
};
|
||||
struct pld_inst {};
|
||||
|
||||
struct sxtb_inst {
|
||||
unsigned int Rd;
|
||||
|
@ -475,7 +471,7 @@ struct pkh_inst {
|
|||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||
#undef VFP_INTERPRETER_STRUCT
|
||||
|
||||
typedef void (*get_addr_fp_t)(ARMul_State *cpu, unsigned int inst, unsigned int &virt_addr);
|
||||
typedef void (*get_addr_fp_t)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr);
|
||||
|
||||
struct ldst_inst {
|
||||
unsigned int inst;
|
||||
|
|
|
@ -16,7 +16,7 @@ enum {
|
|||
R12,
|
||||
R13,
|
||||
LR,
|
||||
R15, //PC,
|
||||
R15, // PC,
|
||||
CPSR_REG,
|
||||
SPSR_REG,
|
||||
|
||||
|
|
|
@ -2,22 +2,20 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/swap.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/arm/skyeye_common/armstate.h"
|
||||
#include <algorithm>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
ARMul_State::ARMul_State(PrivilegeMode initial_mode)
|
||||
{
|
||||
ARMul_State::ARMul_State(PrivilegeMode initial_mode) {
|
||||
Reset();
|
||||
ChangePrivilegeMode(initial_mode);
|
||||
}
|
||||
|
||||
void ARMul_State::ChangePrivilegeMode(u32 new_mode)
|
||||
{
|
||||
void ARMul_State::ChangePrivilegeMode(u32 new_mode) {
|
||||
if (Mode == new_mode)
|
||||
return;
|
||||
|
||||
|
@ -103,8 +101,7 @@ void ARMul_State::ChangePrivilegeMode(u32 new_mode)
|
|||
}
|
||||
|
||||
// Performs a reset
|
||||
void ARMul_State::Reset()
|
||||
{
|
||||
void ARMul_State::Reset() {
|
||||
VFPInit(this);
|
||||
|
||||
// Set stack pointer to the top of the stack
|
||||
|
@ -128,8 +125,7 @@ void ARMul_State::Reset()
|
|||
}
|
||||
|
||||
// Resets certain MPCore CP15 values to their ARM-defined reset values.
|
||||
void ARMul_State::ResetMPCoreCP15Registers()
|
||||
{
|
||||
void ARMul_State::ResetMPCoreCP15Registers() {
|
||||
// c0
|
||||
CP15[CP15_MAIN_ID] = 0x410FB024;
|
||||
CP15[CP15_TLB_TYPE] = 0x00000800;
|
||||
|
@ -185,23 +181,20 @@ void ARMul_State::ResetMPCoreCP15Registers()
|
|||
CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
|
||||
}
|
||||
|
||||
static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type)
|
||||
{
|
||||
static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) {
|
||||
if (GDBStub::g_server_enabled && GDBStub::CheckBreakpoint(address, type)) {
|
||||
LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address);
|
||||
GDBStub::Break(true);
|
||||
}
|
||||
}
|
||||
|
||||
u8 ARMul_State::ReadMemory8(u32 address) const
|
||||
{
|
||||
u8 ARMul_State::ReadMemory8(u32 address) const {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
return Memory::Read8(address);
|
||||
}
|
||||
|
||||
u16 ARMul_State::ReadMemory16(u32 address) const
|
||||
{
|
||||
u16 ARMul_State::ReadMemory16(u32 address) const {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
u16 data = Memory::Read16(address);
|
||||
|
@ -212,8 +205,7 @@ u16 ARMul_State::ReadMemory16(u32 address) const
|
|||
return data;
|
||||
}
|
||||
|
||||
u32 ARMul_State::ReadMemory32(u32 address) const
|
||||
{
|
||||
u32 ARMul_State::ReadMemory32(u32 address) const {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
u32 data = Memory::Read32(address);
|
||||
|
@ -224,8 +216,7 @@ u32 ARMul_State::ReadMemory32(u32 address) const
|
|||
return data;
|
||||
}
|
||||
|
||||
u64 ARMul_State::ReadMemory64(u32 address) const
|
||||
{
|
||||
u64 ARMul_State::ReadMemory64(u32 address) const {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
u64 data = Memory::Read64(address);
|
||||
|
@ -236,15 +227,13 @@ u64 ARMul_State::ReadMemory64(u32 address) const
|
|||
return data;
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory8(u32 address, u8 data)
|
||||
{
|
||||
void ARMul_State::WriteMemory8(u32 address, u8 data) {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
Memory::Write8(address, data);
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory16(u32 address, u16 data)
|
||||
{
|
||||
void ARMul_State::WriteMemory16(u32 address, u16 data) {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
if (InBigEndianMode())
|
||||
|
@ -253,8 +242,7 @@ void ARMul_State::WriteMemory16(u32 address, u16 data)
|
|||
Memory::Write16(address, data);
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory32(u32 address, u32 data)
|
||||
{
|
||||
void ARMul_State::WriteMemory32(u32 address, u32 data) {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
if (InBigEndianMode())
|
||||
|
@ -263,8 +251,7 @@ void ARMul_State::WriteMemory32(u32 address, u32 data)
|
|||
Memory::Write32(address, data);
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory64(u32 address, u64 data)
|
||||
{
|
||||
void ARMul_State::WriteMemory64(u32 address, u64 data) {
|
||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
if (InBigEndianMode())
|
||||
|
@ -273,15 +260,12 @@ void ARMul_State::WriteMemory64(u32 address, u64 data)
|
|||
Memory::Write64(address, data);
|
||||
}
|
||||
|
||||
|
||||
// Reads from the CP15 registers. Used with implementation of the MRC instruction.
|
||||
// Note that since the 3DS does not have the hypervisor extensions, these registers
|
||||
// are not implemented.
|
||||
u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const
|
||||
{
|
||||
u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const {
|
||||
// Unprivileged registers
|
||||
if (crn == 13 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (crn == 13 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 2)
|
||||
return CP15[CP15_THREAD_UPRW];
|
||||
|
||||
|
@ -289,12 +273,9 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
return CP15[CP15_THREAD_URO];
|
||||
}
|
||||
|
||||
if (InAPrivilegedMode())
|
||||
{
|
||||
if (crn == 0 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 0)
|
||||
{
|
||||
if (InAPrivilegedMode()) {
|
||||
if (crn == 0 && opcode_1 == 0) {
|
||||
if (crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_MAIN_ID];
|
||||
|
||||
|
@ -306,9 +287,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
|
||||
if (opcode_2 == 5)
|
||||
return CP15[CP15_CPU_ID];
|
||||
}
|
||||
else if (crm == 1)
|
||||
{
|
||||
} else if (crm == 1) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PROCESSOR_FEATURE_0];
|
||||
|
||||
|
@ -329,9 +308,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
|
||||
if (opcode_2 == 7)
|
||||
return CP15[CP15_MEMORY_MODEL_FEATURE_3];
|
||||
}
|
||||
else if (crm == 2)
|
||||
{
|
||||
} else if (crm == 2) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_ISA_FEATURE_0];
|
||||
|
||||
|
@ -349,8 +326,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
}
|
||||
}
|
||||
|
||||
if (crn == 1 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (crn == 1 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_CONTROL];
|
||||
|
||||
|
@ -361,8 +337,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
return CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
|
||||
}
|
||||
|
||||
if (crn == 2 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (crn == 2 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_TRANSLATION_BASE_TABLE_0];
|
||||
|
||||
|
@ -376,8 +351,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
return CP15[CP15_DOMAIN_ACCESS_CONTROL];
|
||||
|
||||
if (crn == 5 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (crn == 5 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_FAULT_STATUS];
|
||||
|
||||
|
@ -385,8 +359,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
return CP15[CP15_INSTR_FAULT_STATUS];
|
||||
}
|
||||
|
||||
if (crn == 6 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (crn == 6 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_FAULT_ADDRESS];
|
||||
|
||||
|
@ -400,13 +373,11 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
return CP15[CP15_DATA_CACHE_LOCKDOWN];
|
||||
|
||||
if (crn == 10 && opcode_1 == 0)
|
||||
{
|
||||
if (crn == 10 && opcode_1 == 0) {
|
||||
if (crm == 0 && opcode_2 == 0)
|
||||
return CP15[CP15_TLB_LOCKDOWN];
|
||||
|
||||
if (crm == 2)
|
||||
{
|
||||
if (crm == 2) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PRIMARY_REGION_REMAP];
|
||||
|
||||
|
@ -415,8 +386,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
}
|
||||
}
|
||||
|
||||
if (crn == 13 && crm == 0)
|
||||
{
|
||||
if (crn == 13 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PID];
|
||||
|
||||
|
@ -427,10 +397,8 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
return CP15[CP15_THREAD_PRW];
|
||||
}
|
||||
|
||||
if (crn == 15)
|
||||
{
|
||||
if (opcode_1 == 0 && crm == 12)
|
||||
{
|
||||
if (crn == 15) {
|
||||
if (opcode_1 == 0 && crm == 12) {
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
|
||||
|
||||
|
@ -444,8 +412,7 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
return CP15[CP15_COUNT_1];
|
||||
}
|
||||
|
||||
if (opcode_1 == 5 && opcode_2 == 2)
|
||||
{
|
||||
if (opcode_1 == 5 && opcode_2 == 2) {
|
||||
if (crm == 5)
|
||||
return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
|
||||
|
||||
|
@ -461,66 +428,49 @@ u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
|||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
|
||||
LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.",
|
||||
crn, crm, opcode_1, opcode_2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write to the CP15 registers. Used with implementation of the MCR instruction.
|
||||
// Note that since the 3DS does not have the hypervisor extensions, these registers
|
||||
// are not implemented.
|
||||
void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
||||
{
|
||||
if (InAPrivilegedMode())
|
||||
{
|
||||
if (crn == 1 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) {
|
||||
if (InAPrivilegedMode()) {
|
||||
if (crn == 1 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_CONTROL] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_AUXILIARY_CONTROL] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
|
||||
}
|
||||
else if (crn == 2 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
} else if (crn == 2 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
|
||||
}
|
||||
else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
{
|
||||
} else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) {
|
||||
CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
|
||||
}
|
||||
else if (crn == 5 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
} else if (crn == 5 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_FAULT_STATUS] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INSTR_FAULT_STATUS] = value;
|
||||
}
|
||||
else if (crn == 6 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
} else if (crn == 6 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_FAULT_ADDRESS] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_WFAR] = value;
|
||||
}
|
||||
else if (crn == 7 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 0 && opcode_2 == 4)
|
||||
{
|
||||
} else if (crn == 7 && opcode_1 == 0) {
|
||||
if (crm == 0 && opcode_2 == 4) {
|
||||
CP15[CP15_WAIT_FOR_INTERRUPT] = value;
|
||||
}
|
||||
else if (crm == 4 && opcode_2 == 0)
|
||||
{
|
||||
} else if (crm == 4 && opcode_2 == 0) {
|
||||
// NOTE: Not entirely accurate. This should do permission checks.
|
||||
CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
|
||||
}
|
||||
else if (crm == 5)
|
||||
{
|
||||
} else if (crm == 5) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
|
@ -531,31 +481,23 @@ void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u
|
|||
CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
|
||||
else if (opcode_2 == 7)
|
||||
CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
|
||||
}
|
||||
else if (crm == 6)
|
||||
{
|
||||
} else if (crm == 6) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_DATA_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
|
||||
}
|
||||
else if (crm == 7 && opcode_2 == 0)
|
||||
{
|
||||
} else if (crm == 7 && opcode_2 == 0) {
|
||||
CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
|
||||
}
|
||||
else if (crm == 10)
|
||||
{
|
||||
} else if (crm == 10) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_CLEAN_DATA_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
|
||||
}
|
||||
else if (crm == 14)
|
||||
{
|
||||
} else if (crm == 14) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
|
@ -563,11 +505,8 @@ void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u
|
|||
else if (opcode_2 == 2)
|
||||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
|
||||
}
|
||||
}
|
||||
else if (crn == 8 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 5)
|
||||
{
|
||||
} else if (crn == 8 && opcode_1 == 0) {
|
||||
if (crm == 5) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_ITLB] = value;
|
||||
else if (opcode_2 == 1)
|
||||
|
@ -576,9 +515,7 @@ void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u
|
|||
CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
|
||||
}
|
||||
else if (crm == 6)
|
||||
{
|
||||
} else if (crm == 6) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_DTLB] = value;
|
||||
else if (opcode_2 == 1)
|
||||
|
@ -587,9 +524,7 @@ void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u
|
|||
CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
|
||||
}
|
||||
else if (crm == 7)
|
||||
{
|
||||
} else if (crm == 7) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_UTLB] = value;
|
||||
else if (opcode_2 == 1)
|
||||
|
@ -599,27 +534,18 @@ void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u
|
|||
else if (opcode_2 == 3)
|
||||
CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
|
||||
}
|
||||
}
|
||||
else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
{
|
||||
} else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) {
|
||||
CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
|
||||
}
|
||||
else if (crn == 10 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 0 && opcode_2 == 0)
|
||||
{
|
||||
} else if (crn == 10 && opcode_1 == 0) {
|
||||
if (crm == 0 && opcode_2 == 0) {
|
||||
CP15[CP15_TLB_LOCKDOWN] = value;
|
||||
}
|
||||
else if (crm == 2)
|
||||
{
|
||||
} else if (crm == 2) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_PRIMARY_REGION_REMAP] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_NORMAL_REGION_REMAP] = value;
|
||||
}
|
||||
}
|
||||
else if (crn == 13 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
} else if (crn == 13 && opcode_1 == 0 && crm == 0) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_PID] = value;
|
||||
else if (opcode_2 == 1)
|
||||
|
@ -628,11 +554,8 @@ void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u
|
|||
CP15[CP15_THREAD_URO] = value;
|
||||
else if (opcode_2 == 4)
|
||||
CP15[CP15_THREAD_PRW] = value;
|
||||
}
|
||||
else if (crn == 15)
|
||||
{
|
||||
if (opcode_1 == 0 && crm == 12)
|
||||
{
|
||||
} else if (crn == 15) {
|
||||
if (opcode_1 == 0 && crm == 12) {
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
|
||||
else if (opcode_2 == 1)
|
||||
|
@ -641,50 +564,34 @@ void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u
|
|||
CP15[CP15_COUNT_0] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_COUNT_1] = value;
|
||||
}
|
||||
else if (opcode_1 == 5)
|
||||
{
|
||||
if (crm == 4)
|
||||
{
|
||||
} else if (opcode_1 == 5) {
|
||||
if (crm == 4) {
|
||||
if (opcode_2 == 2)
|
||||
CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
|
||||
else if (opcode_2 == 4)
|
||||
CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
|
||||
}
|
||||
else if (crm == 5 && opcode_2 == 2)
|
||||
{
|
||||
} else if (crm == 5 && opcode_2 == 2) {
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
|
||||
}
|
||||
else if (crm == 6 && opcode_2 == 2)
|
||||
{
|
||||
} else if (crm == 6 && opcode_2 == 2) {
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
|
||||
}
|
||||
else if (crm == 7 && opcode_2 == 2)
|
||||
{
|
||||
} else if (crm == 7 && opcode_2 == 2) {
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
|
||||
}
|
||||
}
|
||||
else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
|
||||
{
|
||||
} else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) {
|
||||
CP15[CP15_TLB_DEBUG_CONTROL] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unprivileged registers
|
||||
if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4)
|
||||
{
|
||||
if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) {
|
||||
CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
|
||||
}
|
||||
else if (crn == 7 && opcode_1 == 0 && crm == 10)
|
||||
{
|
||||
} else if (crn == 7 && opcode_1 == 0 && crm == 10) {
|
||||
if (opcode_2 == 4)
|
||||
CP15[CP15_DATA_SYNC_BARRIER] = value;
|
||||
else if (opcode_2 == 5)
|
||||
CP15[CP15_DATA_MEMORY_BARRIER] = value;
|
||||
}
|
||||
else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
|
||||
{
|
||||
} else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) {
|
||||
CP15[CP15_THREAD_UPRW] = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,75 +24,70 @@
|
|||
#include "core/arm/skyeye_common/arm_regformat.h"
|
||||
|
||||
// Signal levels
|
||||
enum {
|
||||
LOW = 0,
|
||||
HIGH = 1,
|
||||
LOWHIGH = 1,
|
||||
HIGHLOW = 2
|
||||
};
|
||||
enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 };
|
||||
|
||||
// Cache types
|
||||
enum {
|
||||
NONCACHE = 0,
|
||||
NONCACHE = 0,
|
||||
DATACACHE = 1,
|
||||
INSTCACHE = 2,
|
||||
};
|
||||
|
||||
// ARM privilege modes
|
||||
enum PrivilegeMode {
|
||||
USER32MODE = 16,
|
||||
FIQ32MODE = 17,
|
||||
IRQ32MODE = 18,
|
||||
SVC32MODE = 19,
|
||||
ABORT32MODE = 23,
|
||||
UNDEF32MODE = 27,
|
||||
USER32MODE = 16,
|
||||
FIQ32MODE = 17,
|
||||
IRQ32MODE = 18,
|
||||
SVC32MODE = 19,
|
||||
ABORT32MODE = 23,
|
||||
UNDEF32MODE = 27,
|
||||
SYSTEM32MODE = 31
|
||||
};
|
||||
|
||||
// ARM privilege mode register banks
|
||||
enum {
|
||||
USERBANK = 0,
|
||||
FIQBANK = 1,
|
||||
IRQBANK = 2,
|
||||
SVCBANK = 3,
|
||||
ABORTBANK = 4,
|
||||
UNDEFBANK = 5,
|
||||
DUMMYBANK = 6,
|
||||
USERBANK = 0,
|
||||
FIQBANK = 1,
|
||||
IRQBANK = 2,
|
||||
SVCBANK = 3,
|
||||
ABORTBANK = 4,
|
||||
UNDEFBANK = 5,
|
||||
DUMMYBANK = 6,
|
||||
SYSTEMBANK = 7
|
||||
};
|
||||
|
||||
// Hardware vector addresses
|
||||
enum {
|
||||
ARMResetV = 0,
|
||||
ARMResetV = 0,
|
||||
ARMUndefinedInstrV = 4,
|
||||
ARMSWIV = 8,
|
||||
ARMPrefetchAbortV = 12,
|
||||
ARMDataAbortV = 16,
|
||||
ARMAddrExceptnV = 20,
|
||||
ARMIRQV = 24,
|
||||
ARMFIQV = 28,
|
||||
ARMErrorV = 32, // This is an offset, not an address!
|
||||
ARMSWIV = 8,
|
||||
ARMPrefetchAbortV = 12,
|
||||
ARMDataAbortV = 16,
|
||||
ARMAddrExceptnV = 20,
|
||||
ARMIRQV = 24,
|
||||
ARMFIQV = 28,
|
||||
ARMErrorV = 32, // This is an offset, not an address!
|
||||
|
||||
ARMul_ResetV = ARMResetV,
|
||||
ARMul_ResetV = ARMResetV,
|
||||
ARMul_UndefinedInstrV = ARMUndefinedInstrV,
|
||||
ARMul_SWIV = ARMSWIV,
|
||||
ARMul_PrefetchAbortV = ARMPrefetchAbortV,
|
||||
ARMul_DataAbortV = ARMDataAbortV,
|
||||
ARMul_AddrExceptnV = ARMAddrExceptnV,
|
||||
ARMul_IRQV = ARMIRQV,
|
||||
ARMul_FIQV = ARMFIQV
|
||||
ARMul_SWIV = ARMSWIV,
|
||||
ARMul_PrefetchAbortV = ARMPrefetchAbortV,
|
||||
ARMul_DataAbortV = ARMDataAbortV,
|
||||
ARMul_AddrExceptnV = ARMAddrExceptnV,
|
||||
ARMul_IRQV = ARMIRQV,
|
||||
ARMul_FIQV = ARMFIQV
|
||||
};
|
||||
|
||||
// Coprocessor status values
|
||||
enum {
|
||||
ARMul_FIRST = 0,
|
||||
ARMul_TRANSFER = 1,
|
||||
ARMul_BUSY = 2,
|
||||
ARMul_DATA = 3,
|
||||
ARMul_FIRST = 0,
|
||||
ARMul_TRANSFER = 1,
|
||||
ARMul_BUSY = 2,
|
||||
ARMul_DATA = 3,
|
||||
ARMul_INTERRUPT = 4,
|
||||
ARMul_DONE = 0,
|
||||
ARMul_CANT = 1,
|
||||
ARMul_INC = 3
|
||||
ARMul_DONE = 0,
|
||||
ARMul_CANT = 1,
|
||||
ARMul_INC = 3
|
||||
};
|
||||
|
||||
// Instruction condition codes
|
||||
|
@ -136,15 +131,13 @@ enum : u32 {
|
|||
|
||||
// Values for Emulate.
|
||||
enum {
|
||||
STOP = 0, // Stop
|
||||
STOP = 0, // Stop
|
||||
CHANGEMODE = 1, // Change mode
|
||||
ONCE = 2, // Execute just one iteration
|
||||
RUN = 3 // Continuous execution
|
||||
ONCE = 2, // Execute just one iteration
|
||||
RUN = 3 // Continuous execution
|
||||
};
|
||||
|
||||
|
||||
struct ARMul_State final
|
||||
{
|
||||
struct ARMul_State final {
|
||||
public:
|
||||
explicit ARMul_State(PrivilegeMode initial_mode);
|
||||
|
||||
|
@ -193,7 +186,7 @@ public:
|
|||
return TFlag ? 2 : 4;
|
||||
}
|
||||
|
||||
std::array<u32, 16> Reg{}; // The current register file
|
||||
std::array<u32, 16> Reg{}; // The current register file
|
||||
std::array<u32, 2> Reg_usr{};
|
||||
std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC
|
||||
std::array<u32, 2> Reg_abort{}; // R13_ABORT R14_ABORT
|
||||
|
@ -216,8 +209,8 @@ public:
|
|||
u32 Spsr_copy;
|
||||
u32 phys_pc;
|
||||
|
||||
u32 Mode; // The current mode
|
||||
u32 Bank; // The current register bank
|
||||
u32 Mode; // The current mode
|
||||
u32 Bank; // The current register bank
|
||||
|
||||
u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
|
||||
unsigned int shifter_carry_out;
|
||||
|
@ -243,8 +236,10 @@ public:
|
|||
private:
|
||||
void ResetMPCoreCP15Registers();
|
||||
|
||||
// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
|
||||
// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
|
||||
// Defines a reservation granule of 2 words, which protects the first 2 words starting at the
|
||||
// tag.
|
||||
// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough
|
||||
// to
|
||||
// support LDR/STREXD.
|
||||
static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@
|
|||
#include "core/arm/skyeye_common/armsupp.h"
|
||||
|
||||
// Unsigned sum of absolute difference
|
||||
u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
|
||||
{
|
||||
u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) {
|
||||
if (left > right)
|
||||
return left - right;
|
||||
|
||||
|
@ -31,8 +30,8 @@ u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
|
|||
}
|
||||
|
||||
// Add with carry, indicates if a carry-out or signed overflow occurred.
|
||||
u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred)
|
||||
{
|
||||
u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred,
|
||||
bool* overflow_occurred) {
|
||||
u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in;
|
||||
s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in;
|
||||
u64 result = (unsigned_sum & 0xFFFFFFFF);
|
||||
|
@ -47,22 +46,17 @@ u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bo
|
|||
}
|
||||
|
||||
// Compute whether an addition of A and B, giving RESULT, overflowed.
|
||||
bool AddOverflow(u32 a, u32 b, u32 result)
|
||||
{
|
||||
return ((NEG(a) && NEG(b) && POS(result)) ||
|
||||
(POS(a) && POS(b) && NEG(result)));
|
||||
bool AddOverflow(u32 a, u32 b, u32 result) {
|
||||
return ((NEG(a) && NEG(b) && POS(result)) || (POS(a) && POS(b) && NEG(result)));
|
||||
}
|
||||
|
||||
// Compute whether a subtraction of A and B, giving RESULT, overflowed.
|
||||
bool SubOverflow(u32 a, u32 b, u32 result)
|
||||
{
|
||||
return ((NEG(a) && POS(b) && POS(result)) ||
|
||||
(POS(a) && NEG(b) && NEG(result)));
|
||||
bool SubOverflow(u32 a, u32 b, u32 result) {
|
||||
return ((NEG(a) && POS(b) && POS(result)) || (POS(a) && NEG(b) && NEG(result)));
|
||||
}
|
||||
|
||||
// Returns true if the Q flag should be set as a result of overflow.
|
||||
bool ARMul_AddOverflowQ(u32 a, u32 b)
|
||||
{
|
||||
bool ARMul_AddOverflowQ(u32 a, u32 b) {
|
||||
u32 result = a + b;
|
||||
if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
|
||||
return true;
|
||||
|
@ -71,8 +65,7 @@ bool ARMul_AddOverflowQ(u32 a, u32 b)
|
|||
}
|
||||
|
||||
// 8-bit signed saturated addition
|
||||
u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
|
||||
{
|
||||
u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) {
|
||||
u8 result = left + right;
|
||||
|
||||
if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
|
||||
|
@ -86,8 +79,7 @@ u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
|
|||
}
|
||||
|
||||
// 8-bit signed saturated subtraction
|
||||
u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
|
||||
{
|
||||
u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) {
|
||||
u8 result = left - right;
|
||||
|
||||
if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
|
||||
|
@ -101,8 +93,7 @@ u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
|
|||
}
|
||||
|
||||
// 16-bit signed saturated addition
|
||||
u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
|
||||
{
|
||||
u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) {
|
||||
u16 result = left + right;
|
||||
|
||||
if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
|
||||
|
@ -116,8 +107,7 @@ u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
|
|||
}
|
||||
|
||||
// 16-bit signed saturated subtraction
|
||||
u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
|
||||
{
|
||||
u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) {
|
||||
u16 result = left - right;
|
||||
|
||||
if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
|
||||
|
@ -131,8 +121,7 @@ u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
|
|||
}
|
||||
|
||||
// 8-bit unsigned saturated addition
|
||||
u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
|
||||
{
|
||||
u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) {
|
||||
u8 result = left + right;
|
||||
|
||||
if (result < left)
|
||||
|
@ -142,8 +131,7 @@ u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
|
|||
}
|
||||
|
||||
// 16-bit unsigned saturated addition
|
||||
u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
|
||||
{
|
||||
u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) {
|
||||
u16 result = left + right;
|
||||
|
||||
if (result < left)
|
||||
|
@ -153,8 +141,7 @@ u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
|
|||
}
|
||||
|
||||
// 8-bit unsigned saturated subtraction
|
||||
u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
|
||||
{
|
||||
u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) {
|
||||
if (left <= right)
|
||||
return 0;
|
||||
|
||||
|
@ -162,8 +149,7 @@ u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
|
|||
}
|
||||
|
||||
// 16-bit unsigned saturated subtraction
|
||||
u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
|
||||
{
|
||||
u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) {
|
||||
if (left <= right)
|
||||
return 0;
|
||||
|
||||
|
@ -171,16 +157,14 @@ u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
|
|||
}
|
||||
|
||||
// Signed saturation.
|
||||
u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
|
||||
{
|
||||
u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) {
|
||||
const u32 max = (1 << shift) - 1;
|
||||
const s32 top = (value >> shift);
|
||||
|
||||
if (top > 0) {
|
||||
*saturation_occurred = true;
|
||||
return max;
|
||||
}
|
||||
else if (top < -1) {
|
||||
} else if (top < -1) {
|
||||
*saturation_occurred = true;
|
||||
return ~max;
|
||||
}
|
||||
|
@ -190,8 +174,7 @@ u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
|
|||
}
|
||||
|
||||
// Unsigned saturation
|
||||
u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
|
||||
{
|
||||
u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) {
|
||||
const u32 max = (1 << shift) - 1;
|
||||
|
||||
if (value < 0) {
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
|
||||
#define BIT(s, n) ((s >> (n)) & 1)
|
||||
|
||||
#define POS(i) ( (~(i)) >> 31 )
|
||||
#define NEG(i) ( (i) >> 31 )
|
||||
#define POS(i) ((~(i)) >> 31)
|
||||
#define NEG(i) ((i) >> 31)
|
||||
|
||||
bool AddOverflow(u32, u32, u32);
|
||||
bool SubOverflow(u32, u32, u32);
|
||||
|
|
|
@ -10,74 +10,74 @@
|
|||
// ARM11 MPCore FPSID Information
|
||||
// Note that these are used as values and not as flags.
|
||||
enum : u32 {
|
||||
VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0
|
||||
VFP_FPSID_SW = 0, // Software emulation bit value
|
||||
VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number
|
||||
VFP_FPSID_PARTNUM = 0x20, // Part number
|
||||
VFP_FPSID_VARIANT = 0xB, // Variant number
|
||||
VFP_FPSID_REVISION = 0x4 // Revision number
|
||||
VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0
|
||||
VFP_FPSID_SW = 0, // Software emulation bit value
|
||||
VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number
|
||||
VFP_FPSID_PARTNUM = 0x20, // Part number
|
||||
VFP_FPSID_VARIANT = 0xB, // Variant number
|
||||
VFP_FPSID_REVISION = 0x4 // Revision number
|
||||
};
|
||||
|
||||
// FPEXC bits
|
||||
enum : u32 {
|
||||
FPEXC_EX = (1U << 31U),
|
||||
FPEXC_EN = (1 << 30),
|
||||
FPEXC_DEX = (1 << 29),
|
||||
FPEXC_FP2V = (1 << 28),
|
||||
FPEXC_VV = (1 << 27),
|
||||
FPEXC_TFV = (1 << 26),
|
||||
FPEXC_LENGTH_BIT = (8),
|
||||
FPEXC_EX = (1U << 31U),
|
||||
FPEXC_EN = (1 << 30),
|
||||
FPEXC_DEX = (1 << 29),
|
||||
FPEXC_FP2V = (1 << 28),
|
||||
FPEXC_VV = (1 << 27),
|
||||
FPEXC_TFV = (1 << 26),
|
||||
FPEXC_LENGTH_BIT = (8),
|
||||
FPEXC_LENGTH_MASK = (7 << FPEXC_LENGTH_BIT),
|
||||
FPEXC_IDF = (1 << 7),
|
||||
FPEXC_IXF = (1 << 4),
|
||||
FPEXC_UFF = (1 << 3),
|
||||
FPEXC_OFF = (1 << 2),
|
||||
FPEXC_DZF = (1 << 1),
|
||||
FPEXC_IOF = (1 << 0),
|
||||
FPEXC_TRAP_MASK = (FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF)
|
||||
FPEXC_IDF = (1 << 7),
|
||||
FPEXC_IXF = (1 << 4),
|
||||
FPEXC_UFF = (1 << 3),
|
||||
FPEXC_OFF = (1 << 2),
|
||||
FPEXC_DZF = (1 << 1),
|
||||
FPEXC_IOF = (1 << 0),
|
||||
FPEXC_TRAP_MASK = (FPEXC_IDF | FPEXC_IXF | FPEXC_UFF | FPEXC_OFF | FPEXC_DZF | FPEXC_IOF)
|
||||
};
|
||||
|
||||
// FPSCR Flags
|
||||
enum : u32 {
|
||||
FPSCR_NFLAG = (1U << 31U), // Negative condition flag
|
||||
FPSCR_ZFLAG = (1 << 30), // Zero condition flag
|
||||
FPSCR_CFLAG = (1 << 29), // Carry condition flag
|
||||
FPSCR_VFLAG = (1 << 28), // Overflow condition flag
|
||||
FPSCR_NFLAG = (1U << 31U), // Negative condition flag
|
||||
FPSCR_ZFLAG = (1 << 30), // Zero condition flag
|
||||
FPSCR_CFLAG = (1 << 29), // Carry condition flag
|
||||
FPSCR_VFLAG = (1 << 28), // Overflow condition flag
|
||||
|
||||
FPSCR_QC = (1 << 27), // Cumulative saturation bit
|
||||
FPSCR_AHP = (1 << 26), // Alternative half-precision control bit
|
||||
FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit
|
||||
FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit
|
||||
FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask
|
||||
FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask
|
||||
FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask
|
||||
FPSCR_QC = (1 << 27), // Cumulative saturation bit
|
||||
FPSCR_AHP = (1 << 26), // Alternative half-precision control bit
|
||||
FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit
|
||||
FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit
|
||||
FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask
|
||||
FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask
|
||||
FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask
|
||||
|
||||
FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable.
|
||||
FPSCR_IXE = (1 << 12), // Inexact exception trap enable
|
||||
FPSCR_UFE = (1 << 11), // Undeflow exception trap enable
|
||||
FPSCR_OFE = (1 << 10), // Overflow exception trap enable
|
||||
FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable
|
||||
FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable
|
||||
FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable.
|
||||
FPSCR_IXE = (1 << 12), // Inexact exception trap enable
|
||||
FPSCR_UFE = (1 << 11), // Undeflow exception trap enable
|
||||
FPSCR_OFE = (1 << 10), // Overflow exception trap enable
|
||||
FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable
|
||||
FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable
|
||||
|
||||
FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit
|
||||
FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit
|
||||
FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit
|
||||
FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit
|
||||
FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit
|
||||
FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit
|
||||
FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit
|
||||
FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit
|
||||
FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit
|
||||
FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit
|
||||
FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit
|
||||
FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit
|
||||
};
|
||||
|
||||
// FPSCR bit offsets
|
||||
enum : u32 {
|
||||
FPSCR_RMODE_BIT = 22,
|
||||
FPSCR_RMODE_BIT = 22,
|
||||
FPSCR_STRIDE_BIT = 20,
|
||||
FPSCR_LENGTH_BIT = 16,
|
||||
};
|
||||
|
||||
// FPSCR rounding modes
|
||||
enum : u32 {
|
||||
FPSCR_ROUND_NEAREST = (0 << 22),
|
||||
FPSCR_ROUND_PLUSINF = (1 << 22),
|
||||
FPSCR_ROUND_NEAREST = (0 << 22),
|
||||
FPSCR_ROUND_PLUSINF = (1 << 22),
|
||||
FPSCR_ROUND_MINUSINF = (2 << 22),
|
||||
FPSCR_ROUND_TOZERO = (3 << 22)
|
||||
FPSCR_ROUND_TOZERO = (3 << 22)
|
||||
};
|
||||
|
|
|
@ -28,15 +28,14 @@
|
|||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||
|
||||
void VFPInit(ARMul_State* state)
|
||||
{
|
||||
state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
|
||||
VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
|
||||
void VFPInit(ARMul_State* state) {
|
||||
state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN << 24 | VFP_FPSID_SW << 23 | VFP_FPSID_SUBARCH << 16 |
|
||||
VFP_FPSID_PARTNUM << 8 | VFP_FPSID_VARIANT << 4 | VFP_FPSID_REVISION;
|
||||
state->VFP[VFP_FPEXC] = 0;
|
||||
state->VFP[VFP_FPSCR] = 0;
|
||||
|
||||
// ARM11 MPCore instruction register reset values.
|
||||
state->VFP[VFP_FPINST] = 0xEE000A00;
|
||||
state->VFP[VFP_FPINST] = 0xEE000A00;
|
||||
state->VFP[VFP_FPINST2] = 0;
|
||||
|
||||
// ARM11 MPCore feature register values.
|
||||
|
@ -44,104 +43,80 @@ void VFPInit(ARMul_State* state)
|
|||
state->VFP[VFP_MVFR1] = 0;
|
||||
}
|
||||
|
||||
void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value)
|
||||
{
|
||||
if (to_arm)
|
||||
{
|
||||
void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value) {
|
||||
if (to_arm) {
|
||||
*value = state->ExtReg[n];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
state->ExtReg[n] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
|
||||
{
|
||||
if (to_arm)
|
||||
{
|
||||
*value2 = state->ExtReg[n*2+1];
|
||||
*value1 = state->ExtReg[n*2];
|
||||
}
|
||||
else
|
||||
{
|
||||
state->ExtReg[n*2+1] = *value2;
|
||||
state->ExtReg[n*2] = *value1;
|
||||
void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) {
|
||||
if (to_arm) {
|
||||
*value2 = state->ExtReg[n * 2 + 1];
|
||||
*value1 = state->ExtReg[n * 2];
|
||||
} else {
|
||||
state->ExtReg[n * 2 + 1] = *value2;
|
||||
state->ExtReg[n * 2] = *value1;
|
||||
}
|
||||
}
|
||||
void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
|
||||
{
|
||||
if (to_arm)
|
||||
{
|
||||
*value1 = state->ExtReg[n+0];
|
||||
*value2 = state->ExtReg[n+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
state->ExtReg[n+0] = *value1;
|
||||
state->ExtReg[n+1] = *value2;
|
||||
void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) {
|
||||
if (to_arm) {
|
||||
*value1 = state->ExtReg[n + 0];
|
||||
*value2 = state->ExtReg[n + 1];
|
||||
} else {
|
||||
state->ExtReg[n + 0] = *value1;
|
||||
state->ExtReg[n + 1] = *value2;
|
||||
}
|
||||
}
|
||||
|
||||
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm)
|
||||
{
|
||||
if (single)
|
||||
{
|
||||
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm) {
|
||||
if (single) {
|
||||
state->ExtReg[d] = imm;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Check endian please */
|
||||
state->ExtReg[d*2+1] = imm;
|
||||
state->ExtReg[d*2] = 0;
|
||||
state->ExtReg[d * 2 + 1] = imm;
|
||||
state->ExtReg[d * 2] = 0;
|
||||
}
|
||||
}
|
||||
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m)
|
||||
{
|
||||
if (single)
|
||||
{
|
||||
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) {
|
||||
if (single) {
|
||||
state->ExtReg[d] = state->ExtReg[m];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Check endian please */
|
||||
state->ExtReg[d*2+1] = state->ExtReg[m*2+1];
|
||||
state->ExtReg[d*2] = state->ExtReg[m*2];
|
||||
state->ExtReg[d * 2 + 1] = state->ExtReg[m * 2 + 1];
|
||||
state->ExtReg[d * 2] = state->ExtReg[m * 2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Miscellaneous functions */
|
||||
s32 vfp_get_float(ARMul_State* state, unsigned int reg)
|
||||
{
|
||||
s32 vfp_get_float(ARMul_State* state, unsigned int reg) {
|
||||
LOG_TRACE(Core_ARM11, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]);
|
||||
return state->ExtReg[reg];
|
||||
}
|
||||
|
||||
void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg)
|
||||
{
|
||||
void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) {
|
||||
LOG_TRACE(Core_ARM11, "VFP put float: s%d <= [%08x]", reg, val);
|
||||
state->ExtReg[reg] = val;
|
||||
}
|
||||
|
||||
u64 vfp_get_double(ARMul_State* state, unsigned int reg)
|
||||
{
|
||||
u64 result = ((u64) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
|
||||
u64 vfp_get_double(ARMul_State* state, unsigned int reg) {
|
||||
u64 result = ((u64)state->ExtReg[reg * 2 + 1]) << 32 | state->ExtReg[reg * 2];
|
||||
LOG_TRACE(Core_ARM11, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg)
|
||||
{
|
||||
LOG_TRACE(Core_ARM11, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2, (u32)(val >> 32), (u32)(val & 0xffffffff));
|
||||
state->ExtReg[reg*2] = (u32) (val & 0xffffffff);
|
||||
state->ExtReg[reg*2+1] = (u32) (val>>32);
|
||||
void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) {
|
||||
LOG_TRACE(Core_ARM11, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2,
|
||||
(u32)(val >> 32), (u32)(val & 0xffffffff));
|
||||
state->ExtReg[reg * 2] = (u32)(val & 0xffffffff);
|
||||
state->ExtReg[reg * 2 + 1] = (u32)(val >> 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process bitmask of exception conditions. (from vfpmodule.c)
|
||||
*/
|
||||
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
|
||||
{
|
||||
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x", exceptions);
|
||||
|
||||
if (exceptions == VFP_EXCEPTION_ERROR) {
|
||||
|
@ -154,8 +129,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
|
|||
* Comparison instructions always return at least one of
|
||||
* these flags set.
|
||||
*/
|
||||
if (exceptions & (FPSCR_NFLAG|FPSCR_ZFLAG|FPSCR_CFLAG|FPSCR_VFLAG))
|
||||
fpscr &= ~(FPSCR_NFLAG|FPSCR_ZFLAG|FPSCR_CFLAG|FPSCR_VFLAG);
|
||||
if (exceptions & (FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG))
|
||||
fpscr &= ~(FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG);
|
||||
|
||||
fpscr |= exceptions;
|
||||
|
||||
|
|
|
@ -37,56 +37,56 @@
|
|||
#include "core/arm/skyeye_common/armstate.h"
|
||||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||
|
||||
#define do_div(n, base) {n/=base;}
|
||||
#define do_div(n, base) \
|
||||
{ n /= base; }
|
||||
|
||||
enum : u32 {
|
||||
FOP_MASK = 0x00b00040,
|
||||
FOP_FMAC = 0x00000000,
|
||||
FOP_MASK = 0x00b00040,
|
||||
FOP_FMAC = 0x00000000,
|
||||
FOP_FNMAC = 0x00000040,
|
||||
FOP_FMSC = 0x00100000,
|
||||
FOP_FMSC = 0x00100000,
|
||||
FOP_FNMSC = 0x00100040,
|
||||
FOP_FMUL = 0x00200000,
|
||||
FOP_FMUL = 0x00200000,
|
||||
FOP_FNMUL = 0x00200040,
|
||||
FOP_FADD = 0x00300000,
|
||||
FOP_FSUB = 0x00300040,
|
||||
FOP_FDIV = 0x00800000,
|
||||
FOP_EXT = 0x00b00040
|
||||
FOP_FADD = 0x00300000,
|
||||
FOP_FSUB = 0x00300040,
|
||||
FOP_FDIV = 0x00800000,
|
||||
FOP_EXT = 0x00b00040
|
||||
};
|
||||
|
||||
#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4)
|
||||
|
||||
enum : u32 {
|
||||
FEXT_MASK = 0x000f0080,
|
||||
FEXT_FCPY = 0x00000000,
|
||||
FEXT_FABS = 0x00000080,
|
||||
FEXT_FNEG = 0x00010000,
|
||||
FEXT_FSQRT = 0x00010080,
|
||||
FEXT_FCMP = 0x00040000,
|
||||
FEXT_FCMPE = 0x00040080,
|
||||
FEXT_FCMPZ = 0x00050000,
|
||||
FEXT_MASK = 0x000f0080,
|
||||
FEXT_FCPY = 0x00000000,
|
||||
FEXT_FABS = 0x00000080,
|
||||
FEXT_FNEG = 0x00010000,
|
||||
FEXT_FSQRT = 0x00010080,
|
||||
FEXT_FCMP = 0x00040000,
|
||||
FEXT_FCMPE = 0x00040080,
|
||||
FEXT_FCMPZ = 0x00050000,
|
||||
FEXT_FCMPEZ = 0x00050080,
|
||||
FEXT_FCVT = 0x00070080,
|
||||
FEXT_FUITO = 0x00080000,
|
||||
FEXT_FSITO = 0x00080080,
|
||||
FEXT_FTOUI = 0x000c0000,
|
||||
FEXT_FCVT = 0x00070080,
|
||||
FEXT_FUITO = 0x00080000,
|
||||
FEXT_FSITO = 0x00080080,
|
||||
FEXT_FTOUI = 0x000c0000,
|
||||
FEXT_FTOUIZ = 0x000c0080,
|
||||
FEXT_FTOSI = 0x000d0000,
|
||||
FEXT_FTOSI = 0x000d0000,
|
||||
FEXT_FTOSIZ = 0x000d0080
|
||||
};
|
||||
|
||||
#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
|
||||
|
||||
#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22)
|
||||
#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18)
|
||||
#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5)
|
||||
#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1)
|
||||
#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
|
||||
#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3)
|
||||
#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22)
|
||||
#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18)
|
||||
#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5)
|
||||
#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1)
|
||||
#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
|
||||
#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3)
|
||||
|
||||
#define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00)
|
||||
#define vfp_single(inst) (((inst)&0x0000f00) == 0xa00)
|
||||
|
||||
inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift)
|
||||
{
|
||||
inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) {
|
||||
if (shift) {
|
||||
if (shift < 32)
|
||||
val = val >> shift | ((val << (32 - shift)) != 0);
|
||||
|
@ -96,8 +96,7 @@ inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift)
|
|||
return val;
|
||||
}
|
||||
|
||||
inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift)
|
||||
{
|
||||
inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) {
|
||||
if (shift) {
|
||||
if (shift < 64)
|
||||
val = val >> shift | ((val << (64 - shift)) != 0);
|
||||
|
@ -107,8 +106,7 @@ inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift)
|
|||
return val;
|
||||
}
|
||||
|
||||
inline u32 vfp_hi64to32jamming(u64 val)
|
||||
{
|
||||
inline u32 vfp_hi64to32jamming(u64 val) {
|
||||
u32 v;
|
||||
u32 highval = val >> 32;
|
||||
u32 lowval = val & 0xffffffff;
|
||||
|
@ -121,24 +119,21 @@ inline u32 vfp_hi64to32jamming(u64 val)
|
|||
return v;
|
||||
}
|
||||
|
||||
inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml)
|
||||
{
|
||||
inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) {
|
||||
*resl = nl + ml;
|
||||
*resh = nh + mh;
|
||||
if (*resl < nl)
|
||||
*resh += 1;
|
||||
}
|
||||
|
||||
inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml)
|
||||
{
|
||||
inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) {
|
||||
*resl = nl - ml;
|
||||
*resh = nh - mh;
|
||||
if (*resl > nl)
|
||||
*resh -= 1;
|
||||
}
|
||||
|
||||
inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m)
|
||||
{
|
||||
inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) {
|
||||
u32 nh, nl, mh, ml;
|
||||
u64 rh, rma, rmb, rl;
|
||||
|
||||
|
@ -164,21 +159,18 @@ inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m)
|
|||
*resh = rh;
|
||||
}
|
||||
|
||||
inline void shift64left(u64* resh, u64* resl, u64 n)
|
||||
{
|
||||
inline void shift64left(u64* resh, u64* resl, u64 n) {
|
||||
*resh = n >> 63;
|
||||
*resl = n << 1;
|
||||
}
|
||||
|
||||
inline u64 vfp_hi64multiply64(u64 n, u64 m)
|
||||
{
|
||||
inline u64 vfp_hi64multiply64(u64 n, u64 m) {
|
||||
u64 rh, rl;
|
||||
mul64to128(&rh, &rl, n, m);
|
||||
return rh | (rl != 0);
|
||||
}
|
||||
|
||||
inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
|
||||
{
|
||||
inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) {
|
||||
u64 mh, ml, remh, reml, termh, terml, z;
|
||||
|
||||
if (nh >= m)
|
||||
|
@ -213,9 +205,9 @@ inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
|
|||
|
||||
// Single-precision
|
||||
struct vfp_single {
|
||||
s16 exponent;
|
||||
u16 sign;
|
||||
u32 significand;
|
||||
s16 exponent;
|
||||
u16 sign;
|
||||
u32 significand;
|
||||
};
|
||||
|
||||
// VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa
|
||||
|
@ -224,33 +216,33 @@ struct vfp_single {
|
|||
// which are not propagated to the float upon packing.
|
||||
#define VFP_SINGLE_MANTISSA_BITS (23)
|
||||
#define VFP_SINGLE_EXPONENT_BITS (8)
|
||||
#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2)
|
||||
#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2)
|
||||
#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1)
|
||||
|
||||
// The bit in an unpacked float which indicates that it is a quiet NaN
|
||||
#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS))
|
||||
#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS))
|
||||
|
||||
// Operations on packed single-precision numbers
|
||||
#define vfp_single_packed_sign(v) ((v) & 0x80000000)
|
||||
#define vfp_single_packed_negate(v) ((v) ^ 0x80000000)
|
||||
#define vfp_single_packed_abs(v) ((v) & ~0x80000000)
|
||||
#define vfp_single_packed_exponent(v) (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1))
|
||||
#define vfp_single_packed_sign(v) ((v)&0x80000000)
|
||||
#define vfp_single_packed_negate(v) ((v) ^ 0x80000000)
|
||||
#define vfp_single_packed_abs(v) ((v) & ~0x80000000)
|
||||
#define vfp_single_packed_exponent(v) \
|
||||
(((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1))
|
||||
#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1))
|
||||
|
||||
enum : u32 {
|
||||
VFP_NUMBER = (1 << 0),
|
||||
VFP_ZERO = (1 << 1),
|
||||
VFP_DENORMAL = (1 << 2),
|
||||
VFP_INFINITY = (1 << 3),
|
||||
VFP_NAN = (1 << 4),
|
||||
VFP_NUMBER = (1 << 0),
|
||||
VFP_ZERO = (1 << 1),
|
||||
VFP_DENORMAL = (1 << 2),
|
||||
VFP_INFINITY = (1 << 3),
|
||||
VFP_NAN = (1 << 4),
|
||||
VFP_NAN_SIGNAL = (1 << 5),
|
||||
|
||||
VFP_QNAN = (VFP_NAN),
|
||||
VFP_SNAN = (VFP_NAN|VFP_NAN_SIGNAL)
|
||||
VFP_QNAN = (VFP_NAN),
|
||||
VFP_SNAN = (VFP_NAN | VFP_NAN_SIGNAL)
|
||||
};
|
||||
|
||||
inline int vfp_single_type(const vfp_single* s)
|
||||
{
|
||||
inline int vfp_single_type(const vfp_single* s) {
|
||||
int type = VFP_NUMBER;
|
||||
if (s->exponent == 255) {
|
||||
if (s->significand == 0)
|
||||
|
@ -271,11 +263,9 @@ inline int vfp_single_type(const vfp_single* s)
|
|||
// Unpack a single-precision float. Note that this returns the magnitude
|
||||
// of the single-precision float mantissa with the 1. if necessary,
|
||||
// aligned to bit 30.
|
||||
inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr)
|
||||
{
|
||||
inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr) {
|
||||
u32 exceptions = 0;
|
||||
s->sign = vfp_single_packed_sign(val) >> 16,
|
||||
s->exponent = vfp_single_packed_exponent(val);
|
||||
s->sign = vfp_single_packed_sign(val) >> 16, s->exponent = vfp_single_packed_exponent(val);
|
||||
|
||||
u32 significand = ((u32)val << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
|
||||
if (s->exponent && s->exponent != 255)
|
||||
|
@ -295,22 +285,20 @@ inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr)
|
|||
|
||||
// Re-pack a single-precision float. This assumes that the float is
|
||||
// already normalised such that the MSB is bit 30, _not_ bit 31.
|
||||
inline s32 vfp_single_pack(const vfp_single* s)
|
||||
{
|
||||
u32 val = (s->sign << 16) +
|
||||
(s->exponent << VFP_SINGLE_MANTISSA_BITS) +
|
||||
inline s32 vfp_single_pack(const vfp_single* s) {
|
||||
u32 val = (s->sign << 16) + (s->exponent << VFP_SINGLE_MANTISSA_BITS) +
|
||||
(s->significand >> VFP_SINGLE_LOW_BITS);
|
||||
return (s32)val;
|
||||
}
|
||||
|
||||
|
||||
u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, const char* func);
|
||||
u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr,
|
||||
const char* func);
|
||||
|
||||
// Double-precision
|
||||
struct vfp_double {
|
||||
s16 exponent;
|
||||
u16 sign;
|
||||
u64 significand;
|
||||
s16 exponent;
|
||||
u16 sign;
|
||||
u64 significand;
|
||||
};
|
||||
|
||||
// VFP_REG_ZERO is a special register number for vfp_get_double
|
||||
|
@ -324,21 +312,21 @@ struct vfp_double {
|
|||
|
||||
#define VFP_DOUBLE_MANTISSA_BITS (52)
|
||||
#define VFP_DOUBLE_EXPONENT_BITS (11)
|
||||
#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2)
|
||||
#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2)
|
||||
#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1)
|
||||
|
||||
// The bit in an unpacked double which indicates that it is a quiet NaN
|
||||
#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS))
|
||||
|
||||
// Operations on packed single-precision numbers
|
||||
#define vfp_double_packed_sign(v) ((v) & (1ULL << 63))
|
||||
#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63))
|
||||
#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63))
|
||||
#define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1))
|
||||
#define vfp_double_packed_sign(v) ((v) & (1ULL << 63))
|
||||
#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63))
|
||||
#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63))
|
||||
#define vfp_double_packed_exponent(v) \
|
||||
(((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1))
|
||||
#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1))
|
||||
|
||||
inline int vfp_double_type(const vfp_double* s)
|
||||
{
|
||||
inline int vfp_double_type(const vfp_double* s) {
|
||||
int type = VFP_NUMBER;
|
||||
if (s->exponent == 2047) {
|
||||
if (s->significand == 0)
|
||||
|
@ -359,8 +347,7 @@ inline int vfp_double_type(const vfp_double* s)
|
|||
// Unpack a double-precision float. Note that this returns the magnitude
|
||||
// of the double-precision float mantissa with the 1. if necessary,
|
||||
// aligned to bit 62.
|
||||
inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr)
|
||||
{
|
||||
inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr) {
|
||||
u32 exceptions = 0;
|
||||
s->sign = vfp_double_packed_sign(val) >> 48;
|
||||
s->exponent = vfp_double_packed_exponent(val);
|
||||
|
@ -383,10 +370,8 @@ inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr)
|
|||
|
||||
// Re-pack a double-precision float. This assumes that the float is
|
||||
// already normalised such that the MSB is bit 30, _not_ bit 31.
|
||||
inline s64 vfp_double_pack(const vfp_double* s)
|
||||
{
|
||||
u64 val = ((u64)s->sign << 48) +
|
||||
((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) +
|
||||
inline s64 vfp_double_pack(const vfp_double* s) {
|
||||
u64 val = ((u64)s->sign << 48) + ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) +
|
||||
(s->significand >> VFP_DOUBLE_LOW_BITS);
|
||||
return (s64)val;
|
||||
}
|
||||
|
@ -407,20 +392,14 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
|
|||
// OP_SD - The instruction exceptionally writes to a single precision result.
|
||||
// OP_DD - The instruction exceptionally writes to a double precision result.
|
||||
// OP_SM - The instruction exceptionally reads from a single precision operand.
|
||||
enum : u32 {
|
||||
OP_SCALAR = (1 << 0),
|
||||
OP_SD = (1 << 1),
|
||||
OP_DD = (1 << 1),
|
||||
OP_SM = (1 << 2)
|
||||
};
|
||||
enum : u32 { OP_SCALAR = (1 << 0), OP_SD = (1 << 1), OP_DD = (1 << 1), OP_SM = (1 << 2) };
|
||||
|
||||
struct op {
|
||||
u32 (* const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr);
|
||||
u32 (*const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr);
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
inline u32 fls(u32 x)
|
||||
{
|
||||
inline u32 fls(u32 x) {
|
||||
int r = 32;
|
||||
|
||||
if (!x)
|
||||
|
@ -446,9 +425,9 @@ inline u32 fls(u32 x)
|
|||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr);
|
||||
u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double *vdm, u32 fpscr);
|
||||
u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, const char* func);
|
||||
u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr);
|
||||
u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr,
|
||||
const char* func);
|
||||
|
|
|
@ -51,26 +51,22 @@
|
|||
* ===========================================================================
|
||||
*/
|
||||
|
||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||
#include <algorithm>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||
#include "core/arm/skyeye_common/vfp/vfp_helper.h"
|
||||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||
#include "core/arm/skyeye_common/vfp/vfp_helper.h"
|
||||
|
||||
static struct vfp_double vfp_double_default_qnan = {
|
||||
2047,
|
||||
0,
|
||||
VFP_DOUBLE_SIGNIFICAND_QNAN,
|
||||
2047, 0, VFP_DOUBLE_SIGNIFICAND_QNAN,
|
||||
};
|
||||
|
||||
static void vfp_double_dump(const char *str, struct vfp_double *d)
|
||||
{
|
||||
LOG_TRACE(Core_ARM11, "VFP: %s: sign=%d exponent=%d significand=%016llx",
|
||||
str, d->sign != 0, d->exponent, d->significand);
|
||||
static void vfp_double_dump(const char* str, struct vfp_double* d) {
|
||||
LOG_TRACE(Core_ARM11, "VFP: %s: sign=%d exponent=%d significand=%016llx", str, d->sign != 0,
|
||||
d->exponent, d->significand);
|
||||
}
|
||||
|
||||
static void vfp_double_normalise_denormal(struct vfp_double *vd)
|
||||
{
|
||||
static void vfp_double_normalise_denormal(struct vfp_double* vd) {
|
||||
int bits = 31 - fls((u32)(vd->significand >> 32));
|
||||
if (bits == 31)
|
||||
bits = 63 - fls((u32)vd->significand);
|
||||
|
@ -85,8 +81,8 @@ static void vfp_double_normalise_denormal(struct vfp_double *vd)
|
|||
vfp_double_dump("normalise_denormal: out", vd);
|
||||
}
|
||||
|
||||
u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, const char *func)
|
||||
{
|
||||
u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double* vd, u32 fpscr,
|
||||
const char* func) {
|
||||
u64 significand, incr;
|
||||
int exponent, shift, underflow;
|
||||
u32 rmode;
|
||||
|
@ -193,7 +189,7 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd,
|
|||
vd->exponent = 2045;
|
||||
vd->significand = 0x7fffffffffffffffULL;
|
||||
} else {
|
||||
vd->exponent = 2047; /* infinity */
|
||||
vd->exponent = 2047; /* infinity */
|
||||
vd->significand = 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -211,8 +207,7 @@ pack:
|
|||
vfp_double_dump("pack: final", vd);
|
||||
{
|
||||
s64 d = vfp_double_pack(vd);
|
||||
LOG_TRACE(Core_ARM11, "VFP: %s: d(d%d)=%016llx exceptions=%08x", func,
|
||||
dd, d, exceptions);
|
||||
LOG_TRACE(Core_ARM11, "VFP: %s: d(d%d)=%016llx exceptions=%08x", func, dd, d, exceptions);
|
||||
vfp_put_double(state, d, dd);
|
||||
}
|
||||
return exceptions;
|
||||
|
@ -222,11 +217,9 @@ pack:
|
|||
* Propagate the NaN, setting exceptions if it is signalling.
|
||||
* 'n' is always a NaN. 'm' may be a number, NaN or infinity.
|
||||
*/
|
||||
static u32
|
||||
vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
|
||||
struct vfp_double *vdm, u32 fpscr)
|
||||
{
|
||||
struct vfp_double *nan;
|
||||
static u32 vfp_propagate_nan(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm,
|
||||
u32 fpscr) {
|
||||
struct vfp_double* nan;
|
||||
int tn, tm = 0;
|
||||
|
||||
tn = vfp_double_type(vdn);
|
||||
|
@ -266,29 +259,25 @@ vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
|
|||
/*
|
||||
* Extended operations
|
||||
*/
|
||||
static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
vfp_put_double(state, vfp_get_double(state, dm), dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
vfp_double vdm, vdd, *vdp;
|
||||
int ret, tm;
|
||||
|
@ -297,17 +286,17 @@ static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32
|
|||
exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr);
|
||||
|
||||
tm = vfp_double_type(&vdm);
|
||||
if (tm & (VFP_NAN|VFP_INFINITY)) {
|
||||
if (tm & (VFP_NAN | VFP_INFINITY)) {
|
||||
vdp = &vdd;
|
||||
|
||||
if (tm & VFP_NAN)
|
||||
ret = vfp_propagate_nan(vdp, &vdm, nullptr, fpscr);
|
||||
else if (vdm.sign == 0) {
|
||||
sqrt_copy:
|
||||
sqrt_copy:
|
||||
vdp = &vdm;
|
||||
ret = 0;
|
||||
} else {
|
||||
sqrt_invalid:
|
||||
sqrt_invalid:
|
||||
vdp = &vfp_double_default_qnan;
|
||||
ret = FPSCR_IOC;
|
||||
}
|
||||
|
@ -381,8 +370,7 @@ sqrt_invalid:
|
|||
* Greater than := C
|
||||
* Unordered := CV
|
||||
*/
|
||||
static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) {
|
||||
s64 d, m;
|
||||
u32 ret = 0;
|
||||
|
||||
|
@ -390,7 +378,8 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u
|
|||
m = vfp_get_double(state, dm);
|
||||
if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
|
||||
ret |= FPSCR_CFLAG | FPSCR_VFLAG;
|
||||
if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
|
||||
if (signal_on_qnan ||
|
||||
!(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
|
||||
/*
|
||||
* Signalling NaN, or signalling on quiet NaN
|
||||
*/
|
||||
|
@ -400,7 +389,8 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u
|
|||
d = vfp_get_double(state, dd);
|
||||
if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
|
||||
ret |= FPSCR_CFLAG | FPSCR_VFLAG;
|
||||
if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
|
||||
if (signal_on_qnan ||
|
||||
!(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
|
||||
/*
|
||||
* Signalling NaN, or signalling on quiet NaN
|
||||
*/
|
||||
|
@ -408,13 +398,13 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u
|
|||
}
|
||||
|
||||
if (ret == 0) {
|
||||
//printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
|
||||
// printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
|
||||
if (d == m || vfp_double_packed_abs(d | m) == 0) {
|
||||
/*
|
||||
* equal
|
||||
*/
|
||||
ret |= FPSCR_ZFLAG | FPSCR_CFLAG;
|
||||
//printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
|
||||
// printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
|
||||
} else if (vfp_double_packed_sign(d ^ m)) {
|
||||
/*
|
||||
* different signs
|
||||
|
@ -446,32 +436,27 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u
|
|||
return ret;
|
||||
}
|
||||
|
||||
static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_compare(state, dd, 0, dm, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_compare(state, dd, 1, dm, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
|
||||
struct vfp_double vdm;
|
||||
struct vfp_single vsd;
|
||||
int tm;
|
||||
|
@ -497,7 +482,7 @@ static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32
|
|||
/*
|
||||
* If we have an infinity or a NaN, the exponent must be 255
|
||||
*/
|
||||
if (tm & (VFP_INFINITY|VFP_NAN)) {
|
||||
if (tm & (VFP_INFINITY | VFP_NAN)) {
|
||||
vsd.exponent = 255;
|
||||
if (tm == VFP_QNAN)
|
||||
vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
|
||||
|
@ -515,8 +500,7 @@ pack_nan:
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
struct vfp_double vdm;
|
||||
u32 exceptions = 0;
|
||||
u32 m = vfp_get_float(state, dm);
|
||||
|
@ -530,8 +514,7 @@ static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
struct vfp_double vdm;
|
||||
u32 exceptions = 0;
|
||||
u32 m = vfp_get_float(state, dm);
|
||||
|
@ -545,8 +528,7 @@ static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
|
||||
struct vfp_double vdm;
|
||||
u32 d, exceptions = 0;
|
||||
int rmode = fpscr & FPSCR_RMODE_MASK;
|
||||
|
@ -628,14 +610,13 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_double_ftoui(state, sd, unused, dm, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
|
||||
return vfp_double_ftoui(state, sd, unused, dm,
|
||||
(fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
|
||||
}
|
||||
|
||||
static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) {
|
||||
struct vfp_double vdm;
|
||||
u32 d, exceptions = 0;
|
||||
int rmode = fpscr & FPSCR_RMODE_MASK;
|
||||
|
@ -661,7 +642,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
|
|||
d = ~d;
|
||||
exceptions |= FPSCR_IOC;
|
||||
} else if (vdm.exponent >= 1023) {
|
||||
int shift = 1023 + 63 - vdm.exponent; /* 58 */
|
||||
int shift = 1023 + 63 - vdm.exponent; /* 58 */
|
||||
u64 rem, incr = 0;
|
||||
|
||||
d = (u32)((vdm.significand << 1) >> shift);
|
||||
|
@ -712,48 +693,46 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_double_ftosi(state, dd, unused, dm, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
|
||||
return vfp_double_ftosi(state, dd, unused, dm,
|
||||
(fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
|
||||
}
|
||||
|
||||
static struct op fops_ext[] = {
|
||||
{ vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY
|
||||
{ vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS
|
||||
{ vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG
|
||||
{ vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
|
||||
{ vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
|
||||
{ vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
|
||||
{ vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
|
||||
{ vfp_double_fuito, OP_SCALAR|OP_SM }, //0x00000010 - FEXT_FUITO
|
||||
{ vfp_double_fsito, OP_SCALAR|OP_SM }, //0x00000011 - FEXT_FSITO
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ vfp_double_ftoui, OP_SCALAR|OP_SD }, //0x00000018 - FEXT_FTOUI
|
||||
{ vfp_double_ftouiz, OP_SCALAR|OP_SD }, //0x00000019 - FEXT_FTOUIZ
|
||||
{ vfp_double_ftosi, OP_SCALAR|OP_SD }, //0x0000001A - FEXT_FTOSI
|
||||
{ vfp_double_ftosiz, OP_SCALAR|OP_SD }, //0x0000001B - FEXT_FTOSIZ
|
||||
{vfp_double_fcpy, 0}, // 0x00000000 - FEXT_FCPY
|
||||
{vfp_double_fabs, 0}, // 0x00000001 - FEXT_FABS
|
||||
{vfp_double_fneg, 0}, // 0x00000002 - FEXT_FNEG
|
||||
{vfp_double_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{vfp_double_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP
|
||||
{vfp_double_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE
|
||||
{vfp_double_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ
|
||||
{vfp_double_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{vfp_double_fcvts, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT
|
||||
{vfp_double_fuito, OP_SCALAR | OP_SM}, // 0x00000010 - FEXT_FUITO
|
||||
{vfp_double_fsito, OP_SCALAR | OP_SM}, // 0x00000011 - FEXT_FSITO
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{vfp_double_ftoui, OP_SCALAR | OP_SD}, // 0x00000018 - FEXT_FTOUI
|
||||
{vfp_double_ftouiz, OP_SCALAR | OP_SD}, // 0x00000019 - FEXT_FTOUIZ
|
||||
{vfp_double_ftosi, OP_SCALAR | OP_SD}, // 0x0000001A - FEXT_FTOSI
|
||||
{vfp_double_ftosiz, OP_SCALAR | OP_SD}, // 0x0000001B - FEXT_FTOSIZ
|
||||
};
|
||||
|
||||
static u32
|
||||
vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
|
||||
struct vfp_double *vdm, u32 fpscr)
|
||||
{
|
||||
struct vfp_double *vdp;
|
||||
static u32 vfp_double_fadd_nonnumber(struct vfp_double* vdd, struct vfp_double* vdn,
|
||||
struct vfp_double* vdm, u32 fpscr) {
|
||||
struct vfp_double* vdp;
|
||||
u32 exceptions = 0;
|
||||
int tn, tm;
|
||||
|
||||
|
@ -791,13 +770,12 @@ vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr)
|
||||
{
|
||||
u32 vfp_double_add(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm,
|
||||
u32 fpscr) {
|
||||
u32 exp_diff;
|
||||
u64 m_sig;
|
||||
|
||||
if (vdn->significand & (1ULL << 63) ||
|
||||
vdm->significand & (1ULL << 63)) {
|
||||
if (vdn->significand & (1ULL << 63) || vdm->significand & (1ULL << 63)) {
|
||||
LOG_INFO(Core_ARM11, "VFP: bad FP values in %s", __func__);
|
||||
vfp_double_dump("VDN", vdn);
|
||||
vfp_double_dump("VDM", vdm);
|
||||
|
@ -841,8 +819,7 @@ u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_dou
|
|||
vdd->sign = vfp_sign_negate(vdd->sign);
|
||||
m_sig = (~m_sig + 1);
|
||||
} else if (m_sig == 0) {
|
||||
vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
|
||||
FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
|
||||
vdd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
|
||||
}
|
||||
} else {
|
||||
m_sig += vdn->significand;
|
||||
|
@ -852,10 +829,8 @@ u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_dou
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32
|
||||
vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
|
||||
struct vfp_double *vdm, u32 fpscr)
|
||||
{
|
||||
u32 vfp_double_multiply(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm,
|
||||
u32 fpscr) {
|
||||
vfp_double_dump("VDN", vdn);
|
||||
vfp_double_dump("VDM", vdm);
|
||||
|
||||
|
@ -908,12 +883,11 @@ vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define NEG_MULTIPLY (1 << 0)
|
||||
#define NEG_SUBTRACT (1 << 1)
|
||||
#define NEG_MULTIPLY (1 << 0)
|
||||
#define NEG_SUBTRACT (1 << 1)
|
||||
|
||||
static u32
|
||||
vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func)
|
||||
{
|
||||
static u32 vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr,
|
||||
u32 negate, const char* func) {
|
||||
struct vfp_double vdd, vdp, vdn, vdm;
|
||||
u32 exceptions = 0;
|
||||
|
||||
|
@ -949,8 +923,7 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f
|
|||
/*
|
||||
* sd = sd + (sn * sm)
|
||||
*/
|
||||
static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
|
||||
}
|
||||
|
@ -958,8 +931,7 @@ static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
|
|||
/*
|
||||
* sd = sd - (sn * sm)
|
||||
*/
|
||||
static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
|
||||
}
|
||||
|
@ -967,8 +939,7 @@ static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpsc
|
|||
/*
|
||||
* sd = -sd + (sn * sm)
|
||||
*/
|
||||
static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
|
||||
}
|
||||
|
@ -976,17 +947,16 @@ static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
|
|||
/*
|
||||
* sd = -sd - (sn * sm)
|
||||
*/
|
||||
static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
|
||||
return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY,
|
||||
"fnmsc");
|
||||
}
|
||||
|
||||
/*
|
||||
* sd = sn * sm
|
||||
*/
|
||||
static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
struct vfp_double vdd, vdn, vdm;
|
||||
u32 exceptions = 0;
|
||||
|
||||
|
@ -1008,8 +978,7 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
|
|||
/*
|
||||
* sd = -(sn * sm)
|
||||
*/
|
||||
static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
struct vfp_double vdd, vdn, vdm;
|
||||
u32 exceptions = 0;
|
||||
|
||||
|
@ -1032,8 +1001,7 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc
|
|||
/*
|
||||
* sd = sn + sm
|
||||
*/
|
||||
static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
struct vfp_double vdd, vdn, vdm;
|
||||
u32 exceptions = 0;
|
||||
|
||||
|
@ -1055,8 +1023,7 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
|
|||
/*
|
||||
* sd = sn - sm
|
||||
*/
|
||||
static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
struct vfp_double vdd, vdn, vdm;
|
||||
u32 exceptions = 0;
|
||||
|
||||
|
@ -1083,8 +1050,7 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
|
|||
/*
|
||||
* sd = sn / sm
|
||||
*/
|
||||
static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) {
|
||||
struct vfp_double vdd, vdn, vdm;
|
||||
u32 exceptions = 0;
|
||||
int tm, tn;
|
||||
|
@ -1114,7 +1080,7 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
|
|||
* If n and m are infinity, the result is invalid
|
||||
* If n and m are zero, the result is invalid
|
||||
*/
|
||||
if (tm & tn & (VFP_INFINITY|VFP_ZERO))
|
||||
if (tm & tn & (VFP_INFINITY | VFP_ZERO))
|
||||
goto invalid;
|
||||
|
||||
/*
|
||||
|
@ -1193,29 +1159,22 @@ invalid:
|
|||
}
|
||||
|
||||
static struct op fops[] = {
|
||||
{ vfp_double_fmac, 0 },
|
||||
{ vfp_double_fmsc, 0 },
|
||||
{ vfp_double_fmul, 0 },
|
||||
{ vfp_double_fadd, 0 },
|
||||
{ vfp_double_fnmac, 0 },
|
||||
{ vfp_double_fnmsc, 0 },
|
||||
{ vfp_double_fnmul, 0 },
|
||||
{ vfp_double_fsub, 0 },
|
||||
{ vfp_double_fdiv, 0 },
|
||||
{vfp_double_fmac, 0}, {vfp_double_fmsc, 0}, {vfp_double_fmul, 0},
|
||||
{vfp_double_fadd, 0}, {vfp_double_fnmac, 0}, {vfp_double_fnmsc, 0},
|
||||
{vfp_double_fnmul, 0}, {vfp_double_fsub, 0}, {vfp_double_fdiv, 0},
|
||||
};
|
||||
|
||||
#define FREG_BANK(x) ((x) & 0x0c)
|
||||
#define FREG_IDX(x) ((x) & 3)
|
||||
#define FREG_BANK(x) ((x)&0x0c)
|
||||
#define FREG_IDX(x) ((x)&3)
|
||||
|
||||
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
||||
{
|
||||
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
|
||||
u32 op = inst & FOP_MASK;
|
||||
u32 exceptions = 0;
|
||||
unsigned int dest;
|
||||
unsigned int dn = vfp_get_dn(inst);
|
||||
unsigned int dm;
|
||||
unsigned int vecitr, veclen, vecstride;
|
||||
struct op *fop;
|
||||
struct op* fop;
|
||||
|
||||
LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__);
|
||||
vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
|
||||
|
@ -1249,7 +1208,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
|||
veclen = fpscr & FPSCR_LENGTH_MASK;
|
||||
|
||||
LOG_TRACE(Core_ARM11, "VFP: vecstride=%u veclen=%u", vecstride,
|
||||
(veclen >> FPSCR_LENGTH_BIT) + 1);
|
||||
(veclen >> FPSCR_LENGTH_BIT) + 1);
|
||||
|
||||
if (!fop->fn) {
|
||||
printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
|
||||
|
@ -1262,17 +1221,14 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
|||
|
||||
type = (fop->flags & OP_SD) ? 's' : 'd';
|
||||
if (op == FOP_EXT)
|
||||
LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = op[%u] (d%u)",
|
||||
vecitr >> FPSCR_LENGTH_BIT,
|
||||
type, dest, dn, dm);
|
||||
LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = op[%u] (d%u)", vecitr >> FPSCR_LENGTH_BIT,
|
||||
type, dest, dn, dm);
|
||||
else
|
||||
LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)",
|
||||
vecitr >> FPSCR_LENGTH_BIT,
|
||||
type, dest, dn, FOP_TO_IDX(op), dm);
|
||||
vecitr >> FPSCR_LENGTH_BIT, type, dest, dn, FOP_TO_IDX(op), dm);
|
||||
|
||||
except = fop->fn(state, dest, dn, dm, fpscr);
|
||||
LOG_TRACE(Core_ARM11, "VFP: itr%d: exceptions=%08x",
|
||||
vecitr >> FPSCR_LENGTH_BIT, except);
|
||||
LOG_TRACE(Core_ARM11, "VFP: itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except);
|
||||
|
||||
exceptions |= except;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -58,24 +58,20 @@
|
|||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/arm/skyeye_common/vfp/vfp_helper.h"
|
||||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||
#include "core/arm/skyeye_common/vfp/vfp_helper.h"
|
||||
|
||||
static struct vfp_single vfp_single_default_qnan = {
|
||||
255,
|
||||
0,
|
||||
VFP_SINGLE_SIGNIFICAND_QNAN,
|
||||
255, 0, VFP_SINGLE_SIGNIFICAND_QNAN,
|
||||
};
|
||||
|
||||
static void vfp_single_dump(const char *str, struct vfp_single *s)
|
||||
{
|
||||
LOG_TRACE(Core_ARM11, "%s: sign=%d exponent=%d significand=%08x",
|
||||
str, s->sign != 0, s->exponent, s->significand);
|
||||
static void vfp_single_dump(const char* str, struct vfp_single* s) {
|
||||
LOG_TRACE(Core_ARM11, "%s: sign=%d exponent=%d significand=%08x", str, s->sign != 0,
|
||||
s->exponent, s->significand);
|
||||
}
|
||||
|
||||
static void vfp_single_normalise_denormal(struct vfp_single *vs)
|
||||
{
|
||||
static void vfp_single_normalise_denormal(struct vfp_single* vs) {
|
||||
int bits = 31 - fls(vs->significand);
|
||||
|
||||
vfp_single_dump("normalise_denormal: in", vs);
|
||||
|
@ -88,9 +84,8 @@ static void vfp_single_normalise_denormal(struct vfp_single *vs)
|
|||
vfp_single_dump("normalise_denormal: out", vs);
|
||||
}
|
||||
|
||||
|
||||
u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, const char *func)
|
||||
{
|
||||
u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single* vs, u32 fpscr,
|
||||
const char* func) {
|
||||
u32 significand, incr, rmode;
|
||||
int exponent, shift, underflow;
|
||||
u32 exceptions = 0;
|
||||
|
@ -199,7 +194,7 @@ u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs,
|
|||
vs->exponent = 253;
|
||||
vs->significand = 0x7fffffff;
|
||||
} else {
|
||||
vs->exponent = 255; /* infinity */
|
||||
vs->exponent = 255; /* infinity */
|
||||
vs->significand = 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -217,8 +212,7 @@ pack:
|
|||
vfp_single_dump("pack: final", vs);
|
||||
{
|
||||
s32 d = vfp_single_pack(vs);
|
||||
LOG_TRACE(Core_ARM11, "%s: d(s%d)=%08x exceptions=%08x", func,
|
||||
sd, d, exceptions);
|
||||
LOG_TRACE(Core_ARM11, "%s: d(s%d)=%08x exceptions=%08x", func, sd, d, exceptions);
|
||||
vfp_put_float(state, d, sd);
|
||||
}
|
||||
|
||||
|
@ -229,11 +223,9 @@ pack:
|
|||
* Propagate the NaN, setting exceptions if it is signalling.
|
||||
* 'n' is always a NaN. 'm' may be a number, NaN or infinity.
|
||||
*/
|
||||
static u32
|
||||
vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
|
||||
struct vfp_single *vsm, u32 fpscr)
|
||||
{
|
||||
struct vfp_single *nan;
|
||||
static u32 vfp_propagate_nan(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm,
|
||||
u32 fpscr) {
|
||||
struct vfp_single* nan;
|
||||
int tn, tm = 0;
|
||||
|
||||
tn = vfp_single_type(vsn);
|
||||
|
@ -270,40 +262,33 @@ vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
|
|||
return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extended operations
|
||||
*/
|
||||
static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
vfp_put_float(state, vfp_single_packed_abs(m), sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
vfp_put_float(state, m, sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
vfp_put_float(state, vfp_single_packed_negate(m), sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u16 sqrt_oddadjust[] = {
|
||||
0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
|
||||
0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
|
||||
};
|
||||
static const u16 sqrt_oddadjust[] = {0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f,
|
||||
0x0236, 0x02e0, 0x039c, 0x0468, 0x0545, 0x0631,
|
||||
0x072b, 0x0832, 0x0946, 0x0a67};
|
||||
|
||||
static const u16 sqrt_evenadjust[] = {
|
||||
0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
|
||||
0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
|
||||
};
|
||||
static const u16 sqrt_evenadjust[] = {0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429,
|
||||
0x0356, 0x029e, 0x0200, 0x0179, 0x0109, 0x00af,
|
||||
0x0068, 0x0034, 0x0012, 0x0002};
|
||||
|
||||
u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
|
||||
{
|
||||
u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) {
|
||||
int index;
|
||||
u32 z, a;
|
||||
|
||||
|
@ -331,25 +316,24 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
|
|||
}
|
||||
}
|
||||
|
||||
static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsm, vsd, *vsp;
|
||||
int ret, tm;
|
||||
u32 exceptions = 0;
|
||||
|
||||
exceptions |= vfp_single_unpack(&vsm, m, fpscr);
|
||||
tm = vfp_single_type(&vsm);
|
||||
if (tm & (VFP_NAN|VFP_INFINITY)) {
|
||||
if (tm & (VFP_NAN | VFP_INFINITY)) {
|
||||
vsp = &vsd;
|
||||
|
||||
if (tm & VFP_NAN)
|
||||
ret = vfp_propagate_nan(vsp, &vsm, nullptr, fpscr);
|
||||
else if (vsm.sign == 0) {
|
||||
sqrt_copy:
|
||||
sqrt_copy:
|
||||
vsp = &vsm;
|
||||
ret = 0;
|
||||
} else {
|
||||
sqrt_invalid:
|
||||
sqrt_invalid:
|
||||
vsp = &vfp_single_default_qnan;
|
||||
ret = FPSCR_IOC;
|
||||
}
|
||||
|
@ -420,15 +404,15 @@ sqrt_invalid:
|
|||
* Greater than := C
|
||||
* Unordered := CV
|
||||
*/
|
||||
static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) {
|
||||
s32 d;
|
||||
u32 ret = 0;
|
||||
|
||||
d = vfp_get_float(state, sd);
|
||||
if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
|
||||
ret |= FPSCR_CFLAG | FPSCR_VFLAG;
|
||||
if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
|
||||
if (signal_on_qnan ||
|
||||
!(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
|
||||
/*
|
||||
* Signalling NaN, or signalling on quiet NaN
|
||||
*/
|
||||
|
@ -437,7 +421,8 @@ static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u3
|
|||
|
||||
if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
|
||||
ret |= FPSCR_CFLAG | FPSCR_VFLAG;
|
||||
if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
|
||||
if (signal_on_qnan ||
|
||||
!(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
|
||||
/*
|
||||
* Signalling NaN, or signalling on quiet NaN
|
||||
*/
|
||||
|
@ -479,28 +464,23 @@ static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u3
|
|||
return ret;
|
||||
}
|
||||
|
||||
static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
return vfp_compare(state, sd, 0, m, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
return vfp_compare(state, sd, 1, m, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
return vfp_compare(state, sd, 0, 0, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
return vfp_compare(state, sd, 1, 0, fpscr);
|
||||
}
|
||||
|
||||
static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsm;
|
||||
struct vfp_double vdd;
|
||||
int tm;
|
||||
|
@ -525,7 +505,7 @@ static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 f
|
|||
/*
|
||||
* If we have an infinity or NaN, the exponent must be 2047.
|
||||
*/
|
||||
if (tm & (VFP_INFINITY|VFP_NAN)) {
|
||||
if (tm & (VFP_INFINITY | VFP_NAN)) {
|
||||
vdd.exponent = 2047;
|
||||
if (tm == VFP_QNAN)
|
||||
vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
|
||||
|
@ -543,8 +523,7 @@ pack_nan:
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
struct vfp_single vs;
|
||||
u32 exceptions = 0;
|
||||
|
||||
|
@ -556,8 +535,7 @@ static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 f
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
struct vfp_single vs;
|
||||
u32 exceptions = 0;
|
||||
|
||||
|
@ -569,8 +547,7 @@ static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 f
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsm;
|
||||
u32 d, exceptions = 0;
|
||||
int rmode = fpscr & FPSCR_RMODE_MASK;
|
||||
|
@ -656,13 +633,11 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
return vfp_single_ftoui(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
|
||||
}
|
||||
|
||||
static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsm;
|
||||
u32 d, exceptions = 0;
|
||||
int rmode = fpscr & FPSCR_RMODE_MASK;
|
||||
|
@ -739,51 +714,44 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) {
|
||||
return vfp_single_ftosi(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO);
|
||||
}
|
||||
|
||||
static struct op fops_ext[] = {
|
||||
{ vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY
|
||||
{ vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS
|
||||
{ vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG
|
||||
{ vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
|
||||
{ vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
|
||||
{ vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
|
||||
{ vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
|
||||
{ vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
|
||||
{ vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ nullptr, 0 },
|
||||
{ vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
|
||||
{ vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
|
||||
{ vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
|
||||
{ vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
|
||||
{vfp_single_fcpy, 0}, // 0x00000000 - FEXT_FCPY
|
||||
{vfp_single_fabs, 0}, // 0x00000001 - FEXT_FABS
|
||||
{vfp_single_fneg, 0}, // 0x00000002 - FEXT_FNEG
|
||||
{vfp_single_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{vfp_single_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP
|
||||
{vfp_single_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE
|
||||
{vfp_single_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ
|
||||
{vfp_single_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{vfp_single_fcvtd, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT
|
||||
{vfp_single_fuito, OP_SCALAR}, // 0x00000010 - FEXT_FUITO
|
||||
{vfp_single_fsito, OP_SCALAR}, // 0x00000011 - FEXT_FSITO
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{nullptr, 0},
|
||||
{vfp_single_ftoui, OP_SCALAR}, // 0x00000018 - FEXT_FTOUI
|
||||
{vfp_single_ftouiz, OP_SCALAR}, // 0x00000019 - FEXT_FTOUIZ
|
||||
{vfp_single_ftosi, OP_SCALAR}, // 0x0000001A - FEXT_FTOSI
|
||||
{vfp_single_ftosiz, OP_SCALAR}, // 0x0000001B - FEXT_FTOSIZ
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static u32
|
||||
vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
|
||||
struct vfp_single *vsm, u32 fpscr)
|
||||
{
|
||||
struct vfp_single *vsp;
|
||||
static u32 vfp_single_fadd_nonnumber(struct vfp_single* vsd, struct vfp_single* vsn,
|
||||
struct vfp_single* vsm, u32 fpscr) {
|
||||
struct vfp_single* vsp;
|
||||
u32 exceptions = 0;
|
||||
int tn, tm;
|
||||
|
||||
|
@ -821,14 +789,11 @@ vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
|
|||
return exceptions;
|
||||
}
|
||||
|
||||
static u32
|
||||
vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
|
||||
struct vfp_single *vsm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_add(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm,
|
||||
u32 fpscr) {
|
||||
u32 exp_diff, m_sig;
|
||||
|
||||
if (vsn->significand & 0x80000000 ||
|
||||
vsm->significand & 0x80000000) {
|
||||
if (vsn->significand & 0x80000000 || vsm->significand & 0x80000000) {
|
||||
LOG_WARNING(Core_ARM11, "bad FP values");
|
||||
vfp_single_dump("VSN", vsn);
|
||||
vfp_single_dump("VSM", vsm);
|
||||
|
@ -872,8 +837,7 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
|
|||
vsd->sign = vfp_sign_negate(vsd->sign);
|
||||
m_sig = (~m_sig + 1);
|
||||
} else if (m_sig == 0) {
|
||||
vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
|
||||
FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
|
||||
vsd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
|
||||
}
|
||||
} else {
|
||||
m_sig = vsn->significand + m_sig;
|
||||
|
@ -883,9 +847,8 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u32
|
||||
vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_multiply(struct vfp_single* vsd, struct vfp_single* vsn,
|
||||
struct vfp_single* vsm, u32 fpscr) {
|
||||
vfp_single_dump("VSN", vsn);
|
||||
vfp_single_dump("VSM", vsm);
|
||||
|
||||
|
@ -938,12 +901,11 @@ vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_s
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define NEG_MULTIPLY (1 << 0)
|
||||
#define NEG_SUBTRACT (1 << 1)
|
||||
#define NEG_MULTIPLY (1 << 0)
|
||||
#define NEG_SUBTRACT (1 << 1)
|
||||
|
||||
static u32
|
||||
vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func)
|
||||
{
|
||||
static u32 vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr,
|
||||
u32 negate, const char* func) {
|
||||
vfp_single vsd, vsp, vsn, vsm;
|
||||
u32 exceptions = 0;
|
||||
s32 v;
|
||||
|
@ -985,8 +947,7 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
|
|||
/*
|
||||
* sd = sd + (sn * sm)
|
||||
*/
|
||||
static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
u32 exceptions = 0;
|
||||
LOG_TRACE(Core_ARM11, "s%u = %08x", sn, sd);
|
||||
exceptions |= vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
|
||||
|
@ -996,8 +957,7 @@ static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
|||
/*
|
||||
* sd = sd - (sn * sm)
|
||||
*/
|
||||
static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
// TODO: this one has its arguments inverted, investigate.
|
||||
LOG_TRACE(Core_ARM11, "s%u = %08x", sd, sn);
|
||||
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
|
||||
|
@ -1006,8 +966,7 @@ static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
|
|||
/*
|
||||
* sd = -sd + (sn * sm)
|
||||
*/
|
||||
static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "s%u = %08x", sn, sd);
|
||||
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
|
||||
}
|
||||
|
@ -1015,17 +974,16 @@ static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
|||
/*
|
||||
* sd = -sd - (sn * sm)
|
||||
*/
|
||||
static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "s%u = %08x", sn, sd);
|
||||
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
|
||||
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY,
|
||||
"fnmsc");
|
||||
}
|
||||
|
||||
/*
|
||||
* sd = sn * sm
|
||||
*/
|
||||
static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsd, vsn, vsm;
|
||||
u32 exceptions = 0;
|
||||
s32 n = vfp_get_float(state, sn);
|
||||
|
@ -1049,8 +1007,7 @@ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
|||
/*
|
||||
* sd = -(sn * sm)
|
||||
*/
|
||||
static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsd, vsn, vsm;
|
||||
u32 exceptions = 0;
|
||||
s32 n = vfp_get_float(state, sn);
|
||||
|
@ -1075,8 +1032,7 @@ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
|
|||
/*
|
||||
* sd = sn + sm
|
||||
*/
|
||||
static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsd, vsn, vsm;
|
||||
u32 exceptions = 0;
|
||||
s32 n = vfp_get_float(state, sn);
|
||||
|
@ -1103,8 +1059,7 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
|||
/*
|
||||
* sd = sn - sm
|
||||
*/
|
||||
static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
LOG_TRACE(Core_ARM11, "s%u = %08x", sn, sd);
|
||||
/*
|
||||
* Subtraction is addition with one sign inverted.
|
||||
|
@ -1118,8 +1073,7 @@ static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
|||
/*
|
||||
* sd = sn / sm
|
||||
*/
|
||||
static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
||||
{
|
||||
static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) {
|
||||
struct vfp_single vsd, vsn, vsm;
|
||||
u32 exceptions = 0;
|
||||
s32 n = vfp_get_float(state, sn);
|
||||
|
@ -1151,7 +1105,7 @@ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
|||
* If n and m are infinity, the result is invalid
|
||||
* If n and m are zero, the result is invalid
|
||||
*/
|
||||
if (tm & tn & (VFP_INFINITY|VFP_ZERO))
|
||||
if (tm & tn & (VFP_INFINITY | VFP_ZERO))
|
||||
goto invalid;
|
||||
|
||||
/*
|
||||
|
@ -1226,29 +1180,22 @@ invalid:
|
|||
}
|
||||
|
||||
static struct op fops[] = {
|
||||
{ vfp_single_fmac, 0 },
|
||||
{ vfp_single_fmsc, 0 },
|
||||
{ vfp_single_fmul, 0 },
|
||||
{ vfp_single_fadd, 0 },
|
||||
{ vfp_single_fnmac, 0 },
|
||||
{ vfp_single_fnmsc, 0 },
|
||||
{ vfp_single_fnmul, 0 },
|
||||
{ vfp_single_fsub, 0 },
|
||||
{ vfp_single_fdiv, 0 },
|
||||
{vfp_single_fmac, 0}, {vfp_single_fmsc, 0}, {vfp_single_fmul, 0},
|
||||
{vfp_single_fadd, 0}, {vfp_single_fnmac, 0}, {vfp_single_fnmsc, 0},
|
||||
{vfp_single_fnmul, 0}, {vfp_single_fsub, 0}, {vfp_single_fdiv, 0},
|
||||
};
|
||||
|
||||
#define FREG_BANK(x) ((x) & 0x18)
|
||||
#define FREG_IDX(x) ((x) & 7)
|
||||
#define FREG_BANK(x) ((x)&0x18)
|
||||
#define FREG_IDX(x) ((x)&7)
|
||||
|
||||
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
||||
{
|
||||
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
|
||||
u32 op = inst & FOP_MASK;
|
||||
u32 exceptions = 0;
|
||||
unsigned int dest;
|
||||
unsigned int sn = vfp_get_sn(inst);
|
||||
unsigned int sm = vfp_get_sm(inst);
|
||||
unsigned int vecitr, veclen, vecstride;
|
||||
struct op *fop;
|
||||
struct op* fop;
|
||||
|
||||
vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
|
||||
|
||||
|
@ -1274,11 +1221,11 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
|||
else
|
||||
veclen = fpscr & FPSCR_LENGTH_MASK;
|
||||
|
||||
LOG_TRACE(Core_ARM11, "vecstride=%u veclen=%u", vecstride,
|
||||
(veclen >> FPSCR_LENGTH_BIT) + 1);
|
||||
LOG_TRACE(Core_ARM11, "vecstride=%u veclen=%u", vecstride, (veclen >> FPSCR_LENGTH_BIT) + 1);
|
||||
|
||||
if (!fop->fn) {
|
||||
LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]);
|
||||
LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst),
|
||||
inst, state->Reg[15]);
|
||||
Crash();
|
||||
goto invalid;
|
||||
}
|
||||
|
@ -1290,17 +1237,14 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
|||
|
||||
type = (fop->flags & OP_DD) ? 'd' : 's';
|
||||
if (op == FOP_EXT)
|
||||
LOG_TRACE(Core_ARM11, "itr%d (%c%u) = op[%u] (s%u=%08x)",
|
||||
vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
|
||||
sm, m);
|
||||
LOG_TRACE(Core_ARM11, "itr%d (%c%u) = op[%u] (s%u=%08x)", vecitr >> FPSCR_LENGTH_BIT,
|
||||
type, dest, sn, sm, m);
|
||||
else
|
||||
LOG_TRACE(Core_ARM11, "itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)",
|
||||
vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
|
||||
FOP_TO_IDX(op), sm, m);
|
||||
vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, FOP_TO_IDX(op), sm, m);
|
||||
|
||||
except = fop->fn(state, dest, sn, m, fpscr);
|
||||
LOG_TRACE(Core_ARM11, "itr%d: exceptions=%08x",
|
||||
vecitr >> FPSCR_LENGTH_BIT, except);
|
||||
LOG_TRACE(Core_ARM11, "itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except);
|
||||
|
||||
exceptions |= except;
|
||||
|
||||
|
|
|
@ -27,7 +27,8 @@ void RunLoop(int tight_loop) {
|
|||
if (GDBStub::g_server_enabled) {
|
||||
GDBStub::HandlePacket();
|
||||
|
||||
// If the loop is halted and we want to step, use a tiny (1) number of instructions to execute.
|
||||
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
|
||||
// execute.
|
||||
// Otherwise get out of the loop function.
|
||||
if (GDBStub::GetCpuHaltFlag()) {
|
||||
if (GDBStub::GetCpuStepFlag()) {
|
||||
|
@ -62,7 +63,7 @@ void SingleStep() {
|
|||
}
|
||||
|
||||
/// Halt the core
|
||||
void Halt(const char *msg) {
|
||||
void Halt(const char* msg) {
|
||||
// TODO(ShizZy): ImplementMe
|
||||
}
|
||||
|
||||
|
|
|
@ -40,13 +40,13 @@ void Start();
|
|||
* is not guaranteed to run, as this will be interrupted preemptively if a hardware update is
|
||||
* requested (e.g. on a thread switch).
|
||||
*/
|
||||
void RunLoop(int tight_loop=1000);
|
||||
void RunLoop(int tight_loop = 1000);
|
||||
|
||||
/// Step the CPU one instruction
|
||||
void SingleStep();
|
||||
|
||||
/// Halt the core
|
||||
void Halt(const char *msg);
|
||||
void Halt(const char* msg);
|
||||
|
||||
/// Kill the core
|
||||
void Stop();
|
||||
|
|
|
@ -21,14 +21,13 @@ int g_clock_rate_arm11 = 268123480;
|
|||
#define INITIAL_SLICE_LENGTH 20000
|
||||
#define MAX_SLICE_LENGTH 100000000
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
struct EventType
|
||||
{
|
||||
EventType() {}
|
||||
namespace CoreTiming {
|
||||
struct EventType {
|
||||
EventType() {
|
||||
}
|
||||
|
||||
EventType(TimedCallback cb, const char* n)
|
||||
: callback(cb), name(n) {}
|
||||
EventType(TimedCallback cb, const char* n) : callback(cb), name(n) {
|
||||
}
|
||||
|
||||
TimedCallback callback;
|
||||
const char* name;
|
||||
|
@ -36,8 +35,7 @@ struct EventType
|
|||
|
||||
static std::vector<EventType> event_types;
|
||||
|
||||
struct BaseEvent
|
||||
{
|
||||
struct BaseEvent {
|
||||
s64 time;
|
||||
u64 userdata;
|
||||
int type;
|
||||
|
@ -200,7 +198,6 @@ u64 GetIdleTicks() {
|
|||
return (u64)idled_cycles;
|
||||
}
|
||||
|
||||
|
||||
// This is to be called when outside threads, such as the graphics thread, wants to
|
||||
// schedule things to be executed on the main thread.
|
||||
void ScheduleEvent_Threadsafe(s64 cycles_into_future, int event_type, u64 userdata) {
|
||||
|
@ -222,12 +219,11 @@ void ScheduleEvent_Threadsafe(s64 cycles_into_future, int event_type, u64 userda
|
|||
// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread
|
||||
// in which case the event will get handled immediately, before returning.
|
||||
void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) {
|
||||
if (false) //Core::IsCPUThread())
|
||||
if (false) // Core::IsCPUThread())
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(external_event_section);
|
||||
event_types[event_type].callback(userdata, 0);
|
||||
}
|
||||
else
|
||||
} else
|
||||
ScheduleEvent_Threadsafe(0, event_type, userdata);
|
||||
}
|
||||
|
||||
|
@ -317,8 +313,7 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!ts_first)
|
||||
{
|
||||
if (!ts_first) {
|
||||
ts_last = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
@ -369,7 +364,7 @@ void RemoveEvent(int event_type) {
|
|||
return;
|
||||
while (first) {
|
||||
if (first->type == event_type) {
|
||||
Event *next = first->next;
|
||||
Event* next = first->next;
|
||||
FreeEvent(first);
|
||||
first = next;
|
||||
} else {
|
||||
|
@ -509,7 +504,8 @@ void Advance() {
|
|||
void LogPendingEvents() {
|
||||
Event* event = first;
|
||||
while (event) {
|
||||
//LOG_TRACE(Core_Timing, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, next->time, next->type);
|
||||
// LOG_TRACE(Core_Timing, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer,
|
||||
// next->time, next->type);
|
||||
event = event->next;
|
||||
}
|
||||
}
|
||||
|
@ -531,7 +527,8 @@ void Idle(int max_idle) {
|
|||
}
|
||||
}
|
||||
|
||||
LOG_TRACE(Core_Timing, "Idle for %" PRId64 " cycles! (%f ms)", cycles_down, cycles_down / (float)(g_clock_rate_arm11 * 0.001f));
|
||||
LOG_TRACE(Core_Timing, "Idle for %" PRId64 " cycles! (%f ms)", cycles_down,
|
||||
cycles_down / (float)(g_clock_rate_arm11 * 0.001f));
|
||||
|
||||
idled_cycles += cycles_down;
|
||||
Core::g_app_core->down_count -= cycles_down;
|
||||
|
@ -551,7 +548,7 @@ std::string GetScheduledEventsSummary() {
|
|||
if (!name)
|
||||
name = "[unknown]";
|
||||
text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
|
||||
(u32)(event->userdata >> 32), (u32)(event->userdata));
|
||||
(u32)(event->userdata >> 32), (u32)(event->userdata));
|
||||
event = event->next;
|
||||
}
|
||||
return text;
|
||||
|
|
|
@ -61,12 +61,11 @@ inline u64 cyclesToMs(s64 cycles) {
|
|||
return cycles / (g_clock_rate_arm11 / 1000);
|
||||
}
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
namespace CoreTiming {
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
typedef void(*MHzChangeCallback)();
|
||||
typedef void (*MHzChangeCallback)();
|
||||
typedef std::function<void(u64 userdata, int cycles_late)> TimedCallback;
|
||||
|
||||
u64 GetTicks();
|
||||
|
@ -81,7 +80,7 @@ u64 GetGlobalTimeUs();
|
|||
*/
|
||||
int RegisterEvent(const char* name, TimedCallback callback);
|
||||
/// For save states.
|
||||
void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback);
|
||||
void RestoreRegisterEvent(int event_type, const char* name, TimedCallback callback);
|
||||
void UnregisterAllEvents();
|
||||
|
||||
/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk,
|
||||
|
@ -128,7 +127,7 @@ void ClearPendingEvents();
|
|||
void LogPendingEvents();
|
||||
|
||||
/// Warning: not included in save states.
|
||||
void RegisterAdvanceCallback(void(*callback)(int cycles_executed));
|
||||
void RegisterAdvanceCallback(void (*callback)(int cycles_executed));
|
||||
void RegisterMHzChangeCallback(MHzChangeCallback callback);
|
||||
|
||||
std::string GetScheduledEventsSummary();
|
||||
|
|
|
@ -12,27 +12,23 @@
|
|||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
Path::Path(LowPathType type, u32 size, u32 pointer) : type(type) {
|
||||
switch (type) {
|
||||
case Binary:
|
||||
{
|
||||
case Binary: {
|
||||
binary.resize(size);
|
||||
Memory::ReadBlock(pointer, binary.data(), binary.size());
|
||||
break;
|
||||
}
|
||||
|
||||
case Char:
|
||||
{
|
||||
case Char: {
|
||||
string.resize(size - 1); // Data is always null-terminated.
|
||||
Memory::ReadBlock(pointer, &string[0], string.size());
|
||||
break;
|
||||
}
|
||||
|
||||
case Wchar:
|
||||
{
|
||||
case Wchar: {
|
||||
u16str.resize(size / 2 - 1); // Data is always null-terminated.
|
||||
Memory::ReadBlock(pointer, &u16str[0], u16str.size() * sizeof(char16_t));
|
||||
break;
|
||||
|
@ -50,8 +46,7 @@ std::string Path::DebugStr() const {
|
|||
return "[Invalid]";
|
||||
case Empty:
|
||||
return "[Empty]";
|
||||
case Binary:
|
||||
{
|
||||
case Binary: {
|
||||
std::stringstream res;
|
||||
res << "[Binary: ";
|
||||
for (unsigned byte : binary)
|
||||
|
@ -73,13 +68,13 @@ std::string Path::AsString() const {
|
|||
case Wchar:
|
||||
return Common::UTF16ToUTF8(u16str);
|
||||
case Empty:
|
||||
return{};
|
||||
return {};
|
||||
case Invalid:
|
||||
case Binary:
|
||||
default:
|
||||
// TODO(yuriks): Add assert
|
||||
LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!");
|
||||
return{};
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,12 +85,12 @@ std::u16string Path::AsU16Str() const {
|
|||
case Wchar:
|
||||
return u16str;
|
||||
case Empty:
|
||||
return{};
|
||||
return {};
|
||||
case Invalid:
|
||||
case Binary:
|
||||
// TODO(yuriks): Add assert
|
||||
LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!");
|
||||
return{};
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,25 +100,23 @@ std::vector<u8> Path::AsBinary() const {
|
|||
return binary;
|
||||
case Char:
|
||||
return std::vector<u8>(string.begin(), string.end());
|
||||
case Wchar:
|
||||
{
|
||||
case Wchar: {
|
||||
// use two u8 for each character of u16str
|
||||
std::vector<u8> to_return(u16str.size() * 2);
|
||||
for (size_t i = 0; i < u16str.size(); ++i) {
|
||||
u16 tmp_char = u16str.at(i);
|
||||
to_return[i*2] = (tmp_char & 0xFF00) >> 8;
|
||||
to_return[i*2 + 1] = (tmp_char & 0x00FF);
|
||||
to_return[i * 2] = (tmp_char & 0xFF00) >> 8;
|
||||
to_return[i * 2 + 1] = (tmp_char & 0x00FF);
|
||||
}
|
||||
return to_return;
|
||||
}
|
||||
case Empty:
|
||||
return{};
|
||||
return {};
|
||||
case Invalid:
|
||||
default:
|
||||
// TODO(yuriks): Add assert
|
||||
LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!");
|
||||
return{};
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,20 +15,13 @@
|
|||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class FileBackend;
|
||||
class DirectoryBackend;
|
||||
|
||||
// Path string type
|
||||
enum LowPathType : u32 {
|
||||
Invalid = 0,
|
||||
Empty = 1,
|
||||
Binary = 2,
|
||||
Char = 3,
|
||||
Wchar = 4
|
||||
};
|
||||
enum LowPathType : u32 { Invalid = 0, Empty = 1, Binary = 2, Char = 3, Wchar = 4 };
|
||||
|
||||
union Mode {
|
||||
u32 hex;
|
||||
|
@ -39,12 +32,17 @@ union Mode {
|
|||
|
||||
class Path {
|
||||
public:
|
||||
Path() : type(Invalid) {}
|
||||
Path(const char* path) : type(Char), string(path) {}
|
||||
Path(std::vector<u8> binary_data) : type(Binary), binary(std::move(binary_data)) {}
|
||||
Path() : type(Invalid) {
|
||||
}
|
||||
Path(const char* path) : type(Char), string(path) {
|
||||
}
|
||||
Path(std::vector<u8> binary_data) : type(Binary), binary(std::move(binary_data)) {
|
||||
}
|
||||
Path(LowPathType type, u32 size, u32 pointer);
|
||||
|
||||
LowPathType GetType() const { return type; }
|
||||
LowPathType GetType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string representation of the path for debugging
|
||||
|
@ -64,10 +62,14 @@ private:
|
|||
};
|
||||
|
||||
struct ArchiveFormatInfo {
|
||||
u32_le total_size; ///< The pre-defined size of the archive, as specified in the Create or Format call
|
||||
u32_le number_directories; ///< The pre-defined number of directories in the archive, as specified in the Create or Format call
|
||||
u32_le number_files; ///< The pre-defined number of files in the archive, as specified in the Create or Format call
|
||||
u8 duplicate_data; ///< Whether the archive should duplicate the data, as specified in the Create or Format call
|
||||
u32_le total_size; ///< The pre-defined size of the archive, as specified in the Create or
|
||||
/// Format call
|
||||
u32_le number_directories; ///< The pre-defined number of directories in the archive, as
|
||||
/// specified in the Create or Format call
|
||||
u32_le number_files; ///< The pre-defined number of files in the archive, as specified in the
|
||||
/// Create or Format call
|
||||
u8 duplicate_data; ///< Whether the archive should duplicate the data, as specified in the
|
||||
/// Create or Format call
|
||||
};
|
||||
static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
|
||||
|
||||
|
@ -87,7 +89,8 @@ public:
|
|||
* @param mode Mode to open the file with
|
||||
* @return Opened file, or error code
|
||||
*/
|
||||
virtual ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const = 0;
|
||||
virtual ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
||||
const Mode mode) const = 0;
|
||||
|
||||
/**
|
||||
* Delete a file specified by its path
|
||||
|
|
|
@ -30,10 +30,11 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path)
|
|||
|
||||
std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
|
||||
if (shared)
|
||||
return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str());
|
||||
return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(),
|
||||
SYSTEM_ID.c_str());
|
||||
|
||||
return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
|
||||
SYSTEM_ID.c_str(), SDCARD_ID.c_str());
|
||||
SYSTEM_ID.c_str(), SDCARD_ID.c_str());
|
||||
}
|
||||
|
||||
Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) {
|
||||
|
@ -54,11 +55,12 @@ Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) {
|
|||
for (unsigned i = 0; i < 4; ++i)
|
||||
binary_path.push_back((high >> (8 * i)) & 0xFF);
|
||||
|
||||
return { binary_path };
|
||||
return {binary_path};
|
||||
}
|
||||
|
||||
ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared)
|
||||
: shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) {
|
||||
ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location,
|
||||
bool shared)
|
||||
: shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) {
|
||||
LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str());
|
||||
}
|
||||
|
||||
|
@ -88,7 +90,8 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons
|
|||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
||||
}
|
||||
|
||||
ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
|
||||
const FileSys::ArchiveFormatInfo& format_info) {
|
||||
// These folders are always created with the ExtSaveData
|
||||
std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";
|
||||
std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";
|
||||
|
@ -115,7 +118,8 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Pat
|
|||
if (!file.IsOpen()) {
|
||||
LOG_ERROR(Service_FS, "Could not open metadata information for archive");
|
||||
// TODO(Subv): Verify error code
|
||||
return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
}
|
||||
|
||||
ArchiveFormatInfo info = {};
|
||||
|
@ -123,7 +127,8 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Pat
|
|||
return MakeResult<ArchiveFormatInfo>(info);
|
||||
}
|
||||
|
||||
void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data, size_t icon_size) {
|
||||
void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data,
|
||||
size_t icon_size) {
|
||||
std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path);
|
||||
FileUtil::IOFile icon_file(game_path + "icon", "wb");
|
||||
icon_file.WriteBytes(icon_data, icon_size);
|
||||
|
|
|
@ -28,13 +28,17 @@ public:
|
|||
*/
|
||||
bool Initialize();
|
||||
|
||||
std::string GetName() const override { return "ExtSaveData"; }
|
||||
std::string GetName() const override {
|
||||
return "ExtSaveData";
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
|
||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
|
||||
|
||||
const std::string& GetMountPoint() const { return mount_point; }
|
||||
const std::string& GetMountPoint() const {
|
||||
return mount_point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the SMDH icon of the ExtSaveData to file
|
||||
|
@ -45,7 +49,8 @@ public:
|
|||
void WriteIcon(const Path& path, const u8* icon_data, size_t icon_size);
|
||||
|
||||
private:
|
||||
bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData archive
|
||||
bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData
|
||||
/// archive
|
||||
|
||||
/**
|
||||
* This holds the full directory path for this archive, it is only set after a successful call
|
||||
|
@ -65,7 +70,8 @@ private:
|
|||
std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path);
|
||||
|
||||
/**
|
||||
* Constructs a path to the base folder to hold concrete ExtSaveData archives in the host file system.
|
||||
* Constructs a path to the base folder to hold concrete ExtSaveData archives in the host file
|
||||
* system.
|
||||
* @param mount_point The base folder where this folder resides, ie. SDMC or NAND.
|
||||
* @param shared Whether this ExtSaveData container is for SharedExtSaveDatas or not.
|
||||
* @returns The path to the base ExtSaveData archives' folder in the host file system
|
||||
|
|
|
@ -28,11 +28,12 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path
|
|||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
||||
}
|
||||
|
||||
ResultCode ArchiveFactory_RomFS::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
ResultCode ArchiveFactory_RomFS::Format(const Path& path,
|
||||
const FileSys::ArchiveFormatInfo& format_info) {
|
||||
LOG_ERROR(Service_FS, "Attempted to format a RomFS archive.");
|
||||
// TODO: Verify error code
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
|
||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
||||
ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_RomFS::GetFormatInfo(const Path& path) const {
|
||||
|
|
|
@ -24,7 +24,9 @@ class ArchiveFactory_RomFS final : public ArchiveFactory {
|
|||
public:
|
||||
ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
|
||||
|
||||
std::string GetName() const override { return "RomFS"; }
|
||||
std::string GetName() const override {
|
||||
return "RomFS";
|
||||
}
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
|
||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
|
||||
|
|
|
@ -22,48 +22,55 @@ namespace FileSys {
|
|||
|
||||
static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
|
||||
return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
|
||||
SYSTEM_ID.c_str(), SDCARD_ID.c_str());
|
||||
SYSTEM_ID.c_str(), SDCARD_ID.c_str());
|
||||
}
|
||||
|
||||
static std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
|
||||
u32 high = (u32)(program_id >> 32);
|
||||
u32 low = (u32)(program_id & 0xFFFFFFFF);
|
||||
return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low);
|
||||
return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high,
|
||||
low);
|
||||
}
|
||||
|
||||
static std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) {
|
||||
u32 high = (u32)(program_id >> 32);
|
||||
u32 low = (u32)(program_id & 0xFFFFFFFF);
|
||||
return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(), high, low);
|
||||
return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(),
|
||||
high, low);
|
||||
}
|
||||
|
||||
ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory)
|
||||
: mount_point(GetSaveDataContainerPath(sdmc_directory)) {
|
||||
: mount_point(GetSaveDataContainerPath(sdmc_directory)) {
|
||||
LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
|
||||
std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
std::string concrete_mount_point =
|
||||
GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
if (!FileUtil::Exists(concrete_mount_point)) {
|
||||
// When a SaveData archive is created for the first time, it is not yet formatted
|
||||
// and the save file/directory structure expected by the game has not yet been initialized.
|
||||
// Returning the NotFormatted error code will signal the game to provision the SaveData archive
|
||||
// Returning the NotFormatted error code will signal the game to provision the SaveData
|
||||
// archive
|
||||
// with the files and folders that it expects.
|
||||
return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
}
|
||||
|
||||
auto archive = std::make_unique<DiskArchive>(std::move(concrete_mount_point));
|
||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
||||
}
|
||||
|
||||
ResultCode ArchiveFactory_SaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
ResultCode ArchiveFactory_SaveData::Format(const Path& path,
|
||||
const FileSys::ArchiveFormatInfo& format_info) {
|
||||
std::string concrete_mount_point =
|
||||
GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
FileUtil::DeleteDirRecursively(concrete_mount_point);
|
||||
FileUtil::CreateFullPath(concrete_mount_point);
|
||||
|
||||
// Write the format metadata
|
||||
std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
std::string metadata_path =
|
||||
GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
FileUtil::IOFile file(metadata_path, "wb");
|
||||
|
||||
if (file.IsOpen()) {
|
||||
|
@ -74,13 +81,15 @@ ResultCode ArchiveFactory_SaveData::Format(const Path& path, const FileSys::Arch
|
|||
}
|
||||
|
||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const {
|
||||
std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
std::string metadata_path =
|
||||
GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
|
||||
FileUtil::IOFile file(metadata_path, "rb");
|
||||
|
||||
if (!file.IsOpen()) {
|
||||
LOG_ERROR(Service_FS, "Could not open metadata information for archive");
|
||||
// TODO(Subv): Verify error code
|
||||
return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
}
|
||||
|
||||
ArchiveFormatInfo info = {};
|
||||
|
|
|
@ -20,7 +20,9 @@ class ArchiveFactory_SaveData final : public ArchiveFactory {
|
|||
public:
|
||||
ArchiveFactory_SaveData(const std::string& mount_point);
|
||||
|
||||
std::string GetName() const override { return "SaveData"; }
|
||||
std::string GetName() const override {
|
||||
return "SaveData";
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
|
||||
|
|
|
@ -25,12 +25,12 @@ static std::string GetSaveDataCheckContainerPath(const std::string& nand_directo
|
|||
}
|
||||
|
||||
static std::string GetSaveDataCheckPath(const std::string& mount_point, u32 high, u32 low) {
|
||||
return Common::StringFromFormat("%s%08x/%08x/content/00000000.app.romfs",
|
||||
mount_point.c_str(), high, low);
|
||||
return Common::StringFromFormat("%s%08x/%08x/content/00000000.app.romfs", mount_point.c_str(),
|
||||
high, low);
|
||||
}
|
||||
|
||||
ArchiveFactory_SaveDataCheck::ArchiveFactory_SaveDataCheck(const std::string& nand_directory) :
|
||||
mount_point(GetSaveDataCheckContainerPath(nand_directory)) {
|
||||
ArchiveFactory_SaveDataCheck::ArchiveFactory_SaveDataCheck(const std::string& nand_directory)
|
||||
: mount_point(GetSaveDataCheckContainerPath(nand_directory)) {
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(const Path& path) {
|
||||
|
@ -48,11 +48,12 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co
|
|||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
||||
}
|
||||
|
||||
ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path,
|
||||
const FileSys::ArchiveFormatInfo& format_info) {
|
||||
LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive.");
|
||||
// TODO: Verify error code
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
|
||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
||||
ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveDataCheck::GetFormatInfo(const Path& path) const {
|
||||
|
|
|
@ -20,7 +20,9 @@ class ArchiveFactory_SaveDataCheck final : public ArchiveFactory {
|
|||
public:
|
||||
ArchiveFactory_SaveDataCheck(const std::string& mount_point);
|
||||
|
||||
std::string GetName() const override { return "SaveDataCheck"; }
|
||||
std::string GetName() const override {
|
||||
return "SaveDataCheck";
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
|
||||
namespace FileSys {
|
||||
|
||||
ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory) : sdmc_directory(sdmc_directory) {
|
||||
ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory)
|
||||
: sdmc_directory(sdmc_directory) {
|
||||
LOG_INFO(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str());
|
||||
}
|
||||
|
||||
|
@ -40,7 +41,8 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path&
|
|||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
||||
}
|
||||
|
||||
ResultCode ArchiveFactory_SDMC::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
ResultCode ArchiveFactory_SDMC::Format(const Path& path,
|
||||
const FileSys::ArchiveFormatInfo& format_info) {
|
||||
// This is kind of an undesirable operation, so let's just ignore it. :)
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,9 @@ public:
|
|||
*/
|
||||
bool Initialize();
|
||||
|
||||
std::string GetName() const override { return "SDMC"; }
|
||||
std::string GetName() const override {
|
||||
return "SDMC";
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
|
||||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
|
||||
|
|
|
@ -45,11 +45,11 @@ Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) {
|
|||
for (unsigned i = 0; i < 4; ++i)
|
||||
binary_path.push_back((low >> (8 * i)) & 0xFF);
|
||||
|
||||
return { binary_path };
|
||||
return {binary_path};
|
||||
}
|
||||
|
||||
ArchiveFactory_SystemSaveData::ArchiveFactory_SystemSaveData(const std::string& nand_path)
|
||||
: base_path(GetSystemSaveDataContainerPath(nand_path)) {
|
||||
: base_path(GetSystemSaveDataContainerPath(nand_path)) {
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(const Path& path) {
|
||||
|
@ -57,13 +57,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c
|
|||
if (!FileUtil::Exists(fullpath)) {
|
||||
// TODO(Subv): Check error code, this one is probably wrong
|
||||
return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
ErrorSummary::InvalidState, ErrorLevel::Status);
|
||||
}
|
||||
auto archive = std::make_unique<DiskArchive>(fullpath);
|
||||
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
|
||||
}
|
||||
|
||||
ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path,
|
||||
const FileSys::ArchiveFormatInfo& format_info) {
|
||||
std::string fullpath = GetSystemSaveDataPath(base_path, path);
|
||||
FileUtil::DeleteDirRecursively(fullpath);
|
||||
FileUtil::CreateFullPath(fullpath);
|
||||
|
|
|
@ -26,7 +26,9 @@ public:
|
|||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
|
||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
|
||||
|
||||
std::string GetName() const override { return "SystemSaveData"; }
|
||||
std::string GetName() const override {
|
||||
return "SystemSaveData";
|
||||
}
|
||||
|
||||
private:
|
||||
std::string base_path;
|
||||
|
@ -42,7 +44,8 @@ private:
|
|||
std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path);
|
||||
|
||||
/**
|
||||
* Constructs a path to the base folder to hold concrete SystemSaveData archives in the host file system.
|
||||
* Constructs a path to the base folder to hold concrete SystemSaveData archives in the host file
|
||||
* system.
|
||||
* @param mount_point The base folder where this folder resides, ie. SDMC or NAND.
|
||||
* @returns The path to the base SystemSaveData archives' folder in the host file system
|
||||
*/
|
||||
|
|
|
@ -19,15 +19,16 @@ const size_t FILENAME_LENGTH = 0x20C / 2;
|
|||
struct Entry {
|
||||
char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated)
|
||||
std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated)
|
||||
char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD)
|
||||
std::array<char, 4> extension; // 8.3 file extension (set to spaces for directories, null-terminated)
|
||||
char unknown2; // unknown (always 0x01)
|
||||
char unknown3; // unknown (0x00 or 0x08)
|
||||
char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD)
|
||||
std::array<char, 4>
|
||||
extension; // 8.3 file extension (set to spaces for directories, null-terminated)
|
||||
char unknown2; // unknown (always 0x01)
|
||||
char unknown3; // unknown (0x00 or 0x08)
|
||||
char is_directory; // directory flag
|
||||
char is_hidden; // hidden flag
|
||||
char is_archive; // archive flag
|
||||
char is_hidden; // hidden flag
|
||||
char is_archive; // archive flag
|
||||
char is_read_only; // read-only flag
|
||||
u64 file_size; // file size (for files only)
|
||||
u64 file_size; // file size (for files only)
|
||||
};
|
||||
static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!");
|
||||
static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry.");
|
||||
|
@ -37,8 +38,10 @@ static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size i
|
|||
|
||||
class DirectoryBackend : NonCopyable {
|
||||
public:
|
||||
DirectoryBackend() { }
|
||||
virtual ~DirectoryBackend() { }
|
||||
DirectoryBackend() {
|
||||
}
|
||||
virtual ~DirectoryBackend() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the directory
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
|
||||
namespace FileSys {
|
||||
|
||||
ResultVal<std::unique_ptr<FileBackend>> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
|
||||
ResultVal<std::unique_ptr<FileBackend>> DiskArchive::OpenFile(const Path& path,
|
||||
const Mode mode) const {
|
||||
LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
|
||||
auto file = std::make_unique<DiskFile>(*this, path, mode);
|
||||
ResultCode result = file->Open();
|
||||
|
@ -30,15 +31,18 @@ ResultCode DiskArchive::DeleteFile(const Path& path) const {
|
|||
std::string file_path = mount_point + path.AsString();
|
||||
|
||||
if (FileUtil::IsDirectory(file_path))
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled,
|
||||
ErrorLevel::Status);
|
||||
|
||||
if (!FileUtil::Exists(file_path))
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||
ErrorLevel::Status);
|
||||
|
||||
if (FileUtil::Delete(file_path))
|
||||
return RESULT_SUCCESS;
|
||||
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled,
|
||||
ErrorLevel::Status);
|
||||
}
|
||||
|
||||
bool DiskArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||
|
@ -53,10 +57,12 @@ ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u64 size) const {
|
|||
std::string full_path = mount_point + path.AsString();
|
||||
|
||||
if (FileUtil::IsDirectory(full_path))
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled,
|
||||
ErrorLevel::Status);
|
||||
|
||||
if (FileUtil::Exists(full_path))
|
||||
return ResultCode(ErrorDescription::FS_AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_AlreadyExists, ErrorModule::FS,
|
||||
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||
|
||||
if (size == 0) {
|
||||
FileUtil::CreateEmptyFile(full_path);
|
||||
|
@ -69,10 +75,10 @@ ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u64 size) const {
|
|||
if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1)
|
||||
return RESULT_SUCCESS;
|
||||
|
||||
return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource, ErrorLevel::Info);
|
||||
return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource,
|
||||
ErrorLevel::Info);
|
||||
}
|
||||
|
||||
|
||||
bool DiskArchive::CreateDirectory(const Path& path) const {
|
||||
return FileUtil::CreateDir(mount_point + path.AsString());
|
||||
}
|
||||
|
@ -106,17 +112,21 @@ DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode
|
|||
|
||||
ResultCode DiskFile::Open() {
|
||||
if (FileUtil::IsDirectory(path))
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled,
|
||||
ErrorLevel::Status);
|
||||
|
||||
// Specifying only the Create flag is invalid
|
||||
if (mode.create_flag && !mode.read_flag && !mode.write_flag) {
|
||||
return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS,
|
||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
}
|
||||
|
||||
if (!FileUtil::Exists(path)) {
|
||||
if (!mode.create_flag) {
|
||||
LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", path.c_str());
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
|
||||
LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.",
|
||||
path.c_str());
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
|
||||
ErrorSummary::NotFound, ErrorLevel::Status);
|
||||
} else {
|
||||
// Create the file
|
||||
FileUtil::CreateEmptyFile(path);
|
||||
|
@ -135,20 +145,24 @@ ResultCode DiskFile::Open() {
|
|||
file = std::make_unique<FileUtil::IOFile>(path, mode_string.c_str());
|
||||
if (file->IsOpen())
|
||||
return RESULT_SUCCESS;
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||
ErrorLevel::Status);
|
||||
}
|
||||
|
||||
ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
|
||||
if (!mode.read_flag && !mode.write_flag)
|
||||
return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS,
|
||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
|
||||
file->Seek(offset, SEEK_SET);
|
||||
return MakeResult<size_t>(file->ReadBytes(buffer, length));
|
||||
}
|
||||
|
||||
ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
|
||||
ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush,
|
||||
const u8* buffer) const {
|
||||
if (!mode.write_flag)
|
||||
return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS,
|
||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
|
||||
file->Seek(offset, SEEK_SET);
|
||||
size_t written = file->WriteBytes(buffer, length);
|
||||
|
@ -198,7 +212,8 @@ u32 DiskDirectory::Read(const u32 count, Entry* entries) {
|
|||
const std::string& filename = file.virtualName;
|
||||
Entry& entry = entries[entries_read];
|
||||
|
||||
LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
|
||||
LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size,
|
||||
file.isDirectory);
|
||||
|
||||
// TODO(Link Mauve): use a proper conversion to UTF-16.
|
||||
for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
|
||||
|
|
|
@ -29,11 +29,15 @@ namespace FileSys {
|
|||
*/
|
||||
class DiskArchive : public ArchiveBackend {
|
||||
public:
|
||||
DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
|
||||
DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {
|
||||
}
|
||||
|
||||
virtual std::string GetName() const override { return "DiskArchive: " + mount_point; }
|
||||
virtual std::string GetName() const override {
|
||||
return "DiskArchive: " + mount_point;
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const override;
|
||||
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
||||
const Mode mode) const override;
|
||||
ResultCode DeleteFile(const Path& path) const override;
|
||||
bool RenameFile(const Path& src_path, const Path& dest_path) const override;
|
||||
bool DeleteDirectory(const Path& path) const override;
|
||||
|
|
|
@ -16,8 +16,10 @@ namespace FileSys {
|
|||
|
||||
class FileBackend : NonCopyable {
|
||||
public:
|
||||
FileBackend() { }
|
||||
virtual ~FileBackend() { }
|
||||
FileBackend() {
|
||||
}
|
||||
virtual ~FileBackend() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the file
|
||||
|
@ -42,7 +44,8 @@ public:
|
|||
* @param buffer Buffer to read data from
|
||||
* @return Number of bytes written, or error code
|
||||
*/
|
||||
virtual ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0;
|
||||
virtual ResultVal<size_t> Write(u64 offset, size_t length, bool flush,
|
||||
const u8* buffer) const = 0;
|
||||
|
||||
/**
|
||||
* Get the size of the file in bytes
|
||||
|
|
|
@ -19,40 +19,49 @@ std::string IVFCArchive::GetName() const {
|
|||
return "IVFC";
|
||||
}
|
||||
|
||||
ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path, const Mode mode) const {
|
||||
return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>(romfs_file, data_offset, data_size));
|
||||
ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path,
|
||||
const Mode mode) const {
|
||||
return MakeResult<std::unique_ptr<FileBackend>>(
|
||||
std::make_unique<IVFCFile>(romfs_file, data_offset, data_size));
|
||||
}
|
||||
|
||||
ResultCode IVFCArchive::DeleteFile(const Path& path) const {
|
||||
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).", GetName().c_str());
|
||||
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).",
|
||||
GetName().c_str());
|
||||
// TODO(Subv): Verify error code
|
||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS,
|
||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
|
||||
ErrorLevel::Status);
|
||||
}
|
||||
|
||||
bool IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
|
||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).", GetName().c_str());
|
||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).",
|
||||
GetName().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IVFCArchive::DeleteDirectory(const Path& path) const {
|
||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).", GetName().c_str());
|
||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).",
|
||||
GetName().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
|
||||
LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).", GetName().c_str());
|
||||
LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).",
|
||||
GetName().c_str());
|
||||
// TODO: Verify error code
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
|
||||
ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
bool IVFCArchive::CreateDirectory(const Path& path) const {
|
||||
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive (%s).", GetName().c_str());
|
||||
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive (%s).",
|
||||
GetName().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).", GetName().c_str());
|
||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).",
|
||||
GetName().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -75,7 +84,8 @@ ResultVal<size_t> IVFCFile::Read(const u64 offset, const size_t length, u8* buff
|
|||
return MakeResult<size_t>(romfs_file->ReadBytes(buffer, read_length));
|
||||
}
|
||||
|
||||
ResultVal<size_t> IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
|
||||
ResultVal<size_t> IVFCFile::Write(const u64 offset, const size_t length, const bool flush,
|
||||
const u8* buffer) const {
|
||||
LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
|
||||
// TODO(Subv): Find error code
|
||||
return MakeResult<size_t>(0);
|
||||
|
|
|
@ -30,11 +30,13 @@ namespace FileSys {
|
|||
class IVFCArchive : public ArchiveBackend {
|
||||
public:
|
||||
IVFCArchive(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
|
||||
: romfs_file(file), data_offset(offset), data_size(size) {}
|
||||
: romfs_file(file), data_offset(offset), data_size(size) {
|
||||
}
|
||||
|
||||
std::string GetName() const override;
|
||||
|
||||
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const override;
|
||||
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
|
||||
const Mode mode) const override;
|
||||
ResultCode DeleteFile(const Path& path) const override;
|
||||
bool RenameFile(const Path& src_path, const Path& dest_path) const override;
|
||||
bool DeleteDirectory(const Path& path) const override;
|
||||
|
@ -53,15 +55,21 @@ protected:
|
|||
class IVFCFile : public FileBackend {
|
||||
public:
|
||||
IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
|
||||
: romfs_file(file), data_offset(offset), data_size(size) {}
|
||||
: romfs_file(file), data_offset(offset), data_size(size) {
|
||||
}
|
||||
|
||||
ResultCode Open() override { return RESULT_SUCCESS; }
|
||||
ResultCode Open() override {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
|
||||
ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
|
||||
u64 GetSize() const override;
|
||||
bool SetSize(u64 size) const override;
|
||||
bool Close() const override { return false; }
|
||||
void Flush() const override { }
|
||||
bool Close() const override {
|
||||
return false;
|
||||
}
|
||||
void Flush() const override {
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<FileUtil::IOFile> romfs_file;
|
||||
|
@ -71,9 +79,15 @@ private:
|
|||
|
||||
class IVFCDirectory : public DirectoryBackend {
|
||||
public:
|
||||
bool Open() override { return false; }
|
||||
u32 Read(const u32 count, Entry* entries) override { return 0; }
|
||||
bool Close() const override { return false; }
|
||||
bool Open() override {
|
||||
return false;
|
||||
}
|
||||
u32 Read(const u32 count, Entry* entries) override {
|
||||
return 0;
|
||||
}
|
||||
bool Close() const override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
|
|
@ -16,25 +16,25 @@
|
|||
|
||||
#ifdef _MSC_VER
|
||||
#include <WinSock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <common/x64/abi.h>
|
||||
#include <io.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define SHUT_RDWR 2
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/core.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
const int GDB_BUFFER_SIZE = 10000;
|
||||
|
||||
|
@ -64,7 +64,7 @@ const u32 FPSCR_REGISTER = 58;
|
|||
// GDB also wants the l character at the start
|
||||
// This XML defines what the registers are for this specific ARM device
|
||||
static const char* target_xml =
|
||||
R"(l<?xml version="1.0"?>
|
||||
R"(l<?xml version="1.0"?>
|
||||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||||
<target version="1.0">
|
||||
<feature name="org.gnu.gdb.arm.core">
|
||||
|
@ -297,7 +297,8 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) {
|
|||
|
||||
auto bp = p.find(addr);
|
||||
if (bp != p.end()) {
|
||||
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: %08x bytes at %08x of type %d\n", bp->second.len, bp->second.addr, type);
|
||||
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: %08x bytes at %08x of type %d\n",
|
||||
bp->second.len, bp->second.addr, type);
|
||||
p.erase(addr);
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +343,9 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) {
|
|||
}
|
||||
|
||||
if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) {
|
||||
LOG_DEBUG(Debug_GDBStub, "Found breakpoint type %d @ %08x, range: %08x - %08x (%d bytes)\n", type, addr, bp->second.addr, bp->second.addr + len, len);
|
||||
LOG_DEBUG(Debug_GDBStub,
|
||||
"Found breakpoint type %d @ %08x, range: %08x - %08x (%d bytes)\n", type,
|
||||
addr, bp->second.addr, bp->second.addr + len, len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -408,12 +411,13 @@ static void HandleQuery() {
|
|||
|
||||
const char* query = reinterpret_cast<const char*>(command_buffer + 1);
|
||||
|
||||
if (strcmp(query, "TStatus") == 0 ) {
|
||||
if (strcmp(query, "TStatus") == 0) {
|
||||
SendReply("T0");
|
||||
} else if (strncmp(query, "Supported:", strlen("Supported:")) == 0) {
|
||||
// PacketSize needs to be large enough for target xml
|
||||
SendReply("PacketSize=800;qXfer:features:read+");
|
||||
} else if (strncmp(query, "Xfer:features:read:target.xml:", strlen("Xfer:features:read:target.xml:")) == 0) {
|
||||
} else if (strncmp(query, "Xfer:features:read:target.xml:",
|
||||
strlen("Xfer:features:read:target.xml:")) == 0) {
|
||||
SendReply(target_xml);
|
||||
} else {
|
||||
SendReply("");
|
||||
|
@ -422,10 +426,8 @@ static void HandleQuery() {
|
|||
|
||||
/// Handle set thread command from gdb client.
|
||||
static void HandleSetThread() {
|
||||
if (memcmp(command_buffer, "Hg0", 3) == 0 ||
|
||||
memcmp(command_buffer, "Hc-1", 4) == 0 ||
|
||||
memcmp(command_buffer, "Hc0", 4) == 0 ||
|
||||
memcmp(command_buffer, "Hc1", 4) == 0) {
|
||||
if (memcmp(command_buffer, "Hg0", 3) == 0 || memcmp(command_buffer, "Hc-1", 4) == 0 ||
|
||||
memcmp(command_buffer, "Hc0", 4) == 0 || memcmp(command_buffer, "Hc1", 4) == 0) {
|
||||
return SendReply("OK");
|
||||
}
|
||||
|
||||
|
@ -444,7 +446,9 @@ static void SendSignal(u32 signal) {
|
|||
|
||||
latest_signal = signal;
|
||||
|
||||
std::string buffer = Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15, htonl(Core::g_app_core->GetPC()), 13, htonl(Core::g_app_core->GetReg(13)));
|
||||
std::string buffer = Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15,
|
||||
htonl(Core::g_app_core->GetPC()), 13,
|
||||
htonl(Core::g_app_core->GetReg(13)));
|
||||
LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str());
|
||||
SendReply(buffer.c_str());
|
||||
}
|
||||
|
@ -456,7 +460,7 @@ static void ReadCommand() {
|
|||
|
||||
u8 c = ReadByte();
|
||||
if (c == '+') {
|
||||
//ignore ack
|
||||
// ignore ack
|
||||
return;
|
||||
} else if (c == 0x03) {
|
||||
LOG_INFO(Debug_GDBStub, "gdb: found break command\n");
|
||||
|
@ -483,8 +487,9 @@ static void ReadCommand() {
|
|||
u8 checksum_calculated = CalculateChecksum(command_buffer, command_length);
|
||||
|
||||
if (checksum_received != checksum_calculated) {
|
||||
LOG_ERROR(Debug_GDBStub, "gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)\n",
|
||||
checksum_calculated, checksum_received, command_buffer, command_length);
|
||||
LOG_ERROR(Debug_GDBStub,
|
||||
"gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)\n",
|
||||
checksum_calculated, checksum_received, command_buffer, command_length);
|
||||
|
||||
command_length = 0;
|
||||
|
||||
|
@ -534,7 +539,9 @@ static void ReadRegister() {
|
|||
} else if (id == CPSR_REGISTER) {
|
||||
IntToGdbHex(reply, Core::g_app_core->GetCPSR());
|
||||
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
|
||||
IntToGdbHex(reply, Core::g_app_core->GetVFPReg(id - CPSR_REGISTER - 1)); // VFP registers should start at 26, so one after CSPR_REGISTER
|
||||
IntToGdbHex(reply, Core::g_app_core->GetVFPReg(
|
||||
id - CPSR_REGISTER -
|
||||
1)); // VFP registers should start at 26, so one after CSPR_REGISTER
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
IntToGdbHex(reply, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR
|
||||
IntToGdbHex(reply + 8, 0);
|
||||
|
@ -617,7 +624,8 @@ static void WriteRegisters() {
|
|||
// Dummy FPA registers, ignore
|
||||
i += 2;
|
||||
} else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) {
|
||||
Core::g_app_core->SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
|
||||
Core::g_app_core->SetVFPReg(reg - CPSR_REGISTER - 1,
|
||||
GdbHexToInt(buffer_ptr + i * CHAR_BIT));
|
||||
i++; // Skip padding
|
||||
} else if (reg == FPSCR_REGISTER) {
|
||||
Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
|
||||
|
@ -631,12 +639,13 @@ static void WriteRegisters() {
|
|||
static void ReadMemory() {
|
||||
static u8 reply[GDB_BUFFER_SIZE - 4];
|
||||
|
||||
auto start_offset = command_buffer+1;
|
||||
auto addr_pos = std::find(start_offset, command_buffer+command_length, ',');
|
||||
auto start_offset = command_buffer + 1;
|
||||
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
||||
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
||||
|
||||
start_offset = addr_pos+1;
|
||||
u32 len = HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
|
||||
start_offset = addr_pos + 1;
|
||||
u32 len =
|
||||
HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
|
||||
|
||||
LOG_DEBUG(Debug_GDBStub, "gdb: addr: %08x len: %08x\n", addr, len);
|
||||
|
||||
|
@ -656,12 +665,12 @@ static void ReadMemory() {
|
|||
|
||||
/// Modify location in memory with data received from the gdb client.
|
||||
static void WriteMemory() {
|
||||
auto start_offset = command_buffer+1;
|
||||
auto addr_pos = std::find(start_offset, command_buffer+command_length, ',');
|
||||
auto start_offset = command_buffer + 1;
|
||||
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
||||
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
||||
|
||||
start_offset = addr_pos+1;
|
||||
auto len_pos = std::find(start_offset, command_buffer+command_length, ':');
|
||||
start_offset = addr_pos + 1;
|
||||
auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
|
||||
u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset));
|
||||
|
||||
u8* dst = Memory::GetPointer(addr);
|
||||
|
@ -720,9 +729,10 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u32 len) {
|
|||
breakpoint.active = true;
|
||||
breakpoint.addr = addr;
|
||||
breakpoint.len = len;
|
||||
p.insert({ addr, breakpoint });
|
||||
p.insert({addr, breakpoint});
|
||||
|
||||
LOG_DEBUG(Debug_GDBStub, "gdb: added %d breakpoint: %08x bytes at %08x\n", type, breakpoint.len, breakpoint.addr);
|
||||
LOG_DEBUG(Debug_GDBStub, "gdb: added %d breakpoint: %08x bytes at %08x\n", type, breakpoint.len,
|
||||
breakpoint.addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -750,12 +760,13 @@ static void AddBreakpoint() {
|
|||
return SendReply("E01");
|
||||
}
|
||||
|
||||
auto start_offset = command_buffer+3;
|
||||
auto addr_pos = std::find(start_offset, command_buffer+command_length, ',');
|
||||
auto start_offset = command_buffer + 3;
|
||||
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
||||
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
||||
|
||||
start_offset = addr_pos+1;
|
||||
u32 len = HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
|
||||
start_offset = addr_pos + 1;
|
||||
u32 len =
|
||||
HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
|
||||
|
||||
if (type == BreakpointType::Access) {
|
||||
// Access is made up of Read and Write types, so add both breakpoints
|
||||
|
@ -798,12 +809,13 @@ static void RemoveBreakpoint() {
|
|||
return SendReply("E01");
|
||||
}
|
||||
|
||||
auto start_offset = command_buffer+3;
|
||||
auto addr_pos = std::find(start_offset, command_buffer+command_length, ',');
|
||||
auto start_offset = command_buffer + 3;
|
||||
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
||||
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
||||
|
||||
start_offset = addr_pos+1;
|
||||
u32 len = HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
|
||||
start_offset = addr_pos + 1;
|
||||
u32 len =
|
||||
HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
|
||||
|
||||
if (type == BreakpointType::Access) {
|
||||
// Access is made up of Read and Write types, so add both breakpoints
|
||||
|
@ -896,8 +908,7 @@ void ToggleServer(bool status) {
|
|||
if (!IsConnected() && Core::g_sys_core != nullptr) {
|
||||
Init();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Stop server
|
||||
if (IsConnected()) {
|
||||
Shutdown();
|
||||
|
@ -943,7 +954,8 @@ static void Init(u16 port) {
|
|||
|
||||
// Set socket to SO_REUSEADDR so it can always bind on the same port
|
||||
int reuse_enabled = 1;
|
||||
if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled, sizeof(reuse_enabled)) < 0) {
|
||||
if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled,
|
||||
sizeof(reuse_enabled)) < 0) {
|
||||
LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option");
|
||||
}
|
||||
|
||||
|
@ -964,13 +976,13 @@ static void Init(u16 port) {
|
|||
socklen_t client_addrlen = sizeof(saddr_client);
|
||||
gdbserver_socket = accept(tmpsock, client_addr, &client_addrlen);
|
||||
if (gdbserver_socket < 0) {
|
||||
// In the case that we couldn't start the server for whatever reason, just start CPU execution like normal.
|
||||
// In the case that we couldn't start the server for whatever reason, just start CPU
|
||||
// execution like normal.
|
||||
halt_loop = false;
|
||||
step_loop = false;
|
||||
|
||||
LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_INFO(Debug_GDBStub, "Client connected.\n");
|
||||
saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr);
|
||||
}
|
||||
|
@ -1018,5 +1030,4 @@ bool GetCpuStepFlag() {
|
|||
void SetCpuStepFlag(bool is_step) {
|
||||
step_loop = is_step;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -13,11 +13,11 @@ namespace GDBStub {
|
|||
|
||||
/// Breakpoint Method
|
||||
enum class BreakpointType {
|
||||
None, ///< None
|
||||
Execute, ///< Execution Breakpoint
|
||||
Read, ///< Read Breakpoint
|
||||
Write, ///< Write Breakpoint
|
||||
Access ///< Access (R/W) Breakpoint
|
||||
None, ///< None
|
||||
Execute, ///< Execution Breakpoint
|
||||
Read, ///< Read Breakpoint
|
||||
Write, ///< Write Breakpoint
|
||||
Access ///< Access (R/W) Breakpoint
|
||||
};
|
||||
|
||||
struct BreakpointAddress {
|
||||
|
@ -25,7 +25,8 @@ struct BreakpointAddress {
|
|||
BreakpointType type;
|
||||
};
|
||||
|
||||
/// If set to false, the server will never be started and no gdbstub-related functions will be executed.
|
||||
/// If set to false, the server will never be started and no gdbstub-related functions will be
|
||||
/// executed.
|
||||
extern std::atomic<bool> g_server_enabled;
|
||||
|
||||
/**
|
||||
|
@ -92,5 +93,4 @@ bool GetCpuStepFlag();
|
|||
* @param is_step
|
||||
*/
|
||||
void SetCpuStepFlag(bool is_step);
|
||||
|
||||
}
|
||||
|
|
|
@ -23,23 +23,24 @@
|
|||
// Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
|
||||
// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Service::APT::AppletId> {
|
||||
typedef Service::APT::AppletId argument_type;
|
||||
typedef std::size_t result_type;
|
||||
template <>
|
||||
struct hash<Service::APT::AppletId> {
|
||||
typedef Service::APT::AppletId argument_type;
|
||||
typedef std::size_t result_type;
|
||||
|
||||
result_type operator()(const argument_type& id_code) const {
|
||||
typedef std::underlying_type<argument_type>::type Type;
|
||||
return std::hash<Type>()(static_cast<Type>(id_code));
|
||||
}
|
||||
};
|
||||
result_type operator()(const argument_type& id_code) const {
|
||||
typedef std::underlying_type<argument_type>::type Type;
|
||||
return std::hash<Type>()(static_cast<Type>(id_code));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace HLE {
|
||||
namespace Applets {
|
||||
|
||||
static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
|
||||
static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
|
||||
static u32 applet_update_event =
|
||||
-1; ///< The CoreTiming event identifier for the Applet update callback.
|
||||
/// The interval at which the Applet update callback will be called, 16.6ms
|
||||
static const u64 applet_update_interval_us = 16666;
|
||||
|
||||
|
@ -60,7 +61,8 @@ ResultCode Applet::Create(Service::APT::AppletId id) {
|
|||
default:
|
||||
LOG_ERROR(Service_APT, "Could not create applet %u", id);
|
||||
// TODO(Subv): Find the right error code
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet,
|
||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
|
@ -84,7 +86,7 @@ static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
|
|||
// If the applet is still running after the last update, reschedule the event
|
||||
if (applet->IsRunning()) {
|
||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
|
||||
applet_update_event, applet_id);
|
||||
applet_update_event, applet_id);
|
||||
} else {
|
||||
// Otherwise the applet has terminated, in which case we should clean it up
|
||||
applets[id] = nullptr;
|
||||
|
@ -96,7 +98,8 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter)
|
|||
if (result.IsError())
|
||||
return result;
|
||||
// Schedule the update event
|
||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
|
||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event,
|
||||
static_cast<u64>(id));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -116,6 +119,5 @@ void Init() {
|
|||
void Shutdown() {
|
||||
CoreTiming::RemoveEvent(applet_update_event);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -14,8 +14,10 @@ namespace Applets {
|
|||
|
||||
class Applet {
|
||||
public:
|
||||
virtual ~Applet() { }
|
||||
Applet(Service::APT::AppletId id) : id(id) { }
|
||||
virtual ~Applet() {
|
||||
}
|
||||
Applet(Service::APT::AppletId id) : id(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of the Applet subclass identified by the parameter.
|
||||
|
@ -64,7 +66,7 @@ protected:
|
|||
*/
|
||||
virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
|
||||
|
||||
Service::APT::AppletId id; ///< Id of this Applet
|
||||
Service::APT::AppletId id; ///< Id of this Applet
|
||||
std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
|
||||
};
|
||||
|
||||
|
@ -76,6 +78,5 @@ void Init();
|
|||
|
||||
/// Shuts down the HLE applets
|
||||
void Shutdown();
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -18,7 +18,8 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
|
|||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared
|
||||
// memory.
|
||||
// Create the SharedMemory that will hold the framebuffer data
|
||||
Service::APT::CaptureBufferInfo capture_info;
|
||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||
|
@ -30,9 +31,9 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
|
|||
// Allocate a heap block of the required size for this applet.
|
||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||
// Create a SharedMemory that directly points to this heap block.
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
"ErrEula Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
||||
heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "ErrEula Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
|
@ -49,7 +50,8 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
|
|||
ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
|
||||
started = true;
|
||||
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the application.
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
|
||||
// application.
|
||||
// TODO(Subv): Reverse the parameter format for the ErrEula applet
|
||||
|
||||
// Let the application know that we're closing
|
||||
|
|
|
@ -12,16 +12,21 @@ namespace Applets {
|
|||
|
||||
class ErrEula final : public Applet {
|
||||
public:
|
||||
explicit ErrEula(Service::APT::AppletId id): Applet(id) { }
|
||||
explicit ErrEula(Service::APT::AppletId id) : Applet(id) {
|
||||
}
|
||||
|
||||
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
|
||||
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
|
||||
void Update() override;
|
||||
bool IsRunning() const override { return started; }
|
||||
bool IsRunning() const override {
|
||||
return started;
|
||||
}
|
||||
|
||||
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
|
||||
/// It holds the framebuffer info retrieved by the application with GSPGPU::ImportDisplayCaptureInfo
|
||||
/// It holds the framebuffer info retrieved by the application with
|
||||
/// GSPGPU::ImportDisplayCaptureInfo
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
|
||||
|
||||
private:
|
||||
/// Whether this applet is currently running instead of the host application or not.
|
||||
bool started = false;
|
||||
|
|
|
@ -29,7 +29,8 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
|||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared
|
||||
// memory.
|
||||
// Create the SharedMemory that will hold the framebuffer data
|
||||
Service::APT::CaptureBufferInfo capture_info;
|
||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||
|
@ -40,9 +41,9 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
|||
// Allocate a heap block of the required size for this applet.
|
||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||
// Create a SharedMemory that directly points to this heap block.
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
"MiiSelector Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
||||
heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "MiiSelector Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
|
@ -59,12 +60,14 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
|||
ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
|
||||
started = true;
|
||||
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the application.
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
|
||||
// application.
|
||||
// TODO(Subv): Reverse the parameter format for the Mii Selector
|
||||
|
||||
memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
||||
|
||||
// TODO(Subv): Find more about this structure, result code 0 is enough to let most games continue.
|
||||
// TODO(Subv): Find more about this structure, result code 0 is enough to let most games
|
||||
// continue.
|
||||
MiiResult result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
result.result_code = 0;
|
||||
|
@ -84,6 +87,5 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa
|
|||
|
||||
void MiiSelector::Update() {
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/applets/applet.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
@ -17,28 +17,30 @@ namespace HLE {
|
|||
namespace Applets {
|
||||
|
||||
struct MiiConfig {
|
||||
u8 unk_000;
|
||||
u8 unk_001;
|
||||
u8 unk_002;
|
||||
u8 unk_003;
|
||||
u8 unk_004;
|
||||
u8 unk_000;
|
||||
u8 unk_001;
|
||||
u8 unk_002;
|
||||
u8 unk_003;
|
||||
u8 unk_004;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u16 unk_008;
|
||||
INSERT_PADDING_BYTES(0x82);
|
||||
u8 unk_08C;
|
||||
u8 unk_08C;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u16 unk_090;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
u32 unk_094;
|
||||
u16 unk_098;
|
||||
u8 unk_09A[0x64];
|
||||
u8 unk_0FE;
|
||||
u8 unk_0FF;
|
||||
u8 unk_09A[0x64];
|
||||
u8 unk_0FE;
|
||||
u8 unk_0FF;
|
||||
u32 unk_100;
|
||||
};
|
||||
|
||||
static_assert(sizeof(MiiConfig) == 0x104, "MiiConfig structure has incorrect size");
|
||||
#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(MiiConfig, field_name) == position, "Field "#field_name" has invalid position")
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
static_assert(offsetof(MiiConfig, field_name) == position, \
|
||||
"Field " #field_name " has invalid position")
|
||||
ASSERT_REG_POSITION(unk_008, 0x08);
|
||||
ASSERT_REG_POSITION(unk_08C, 0x8C);
|
||||
ASSERT_REG_POSITION(unk_090, 0x90);
|
||||
|
@ -55,22 +57,28 @@ struct MiiResult {
|
|||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size");
|
||||
#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(MiiResult, field_name) == position, "Field "#field_name" has invalid position")
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
static_assert(offsetof(MiiResult, field_name) == position, \
|
||||
"Field " #field_name " has invalid position")
|
||||
ASSERT_REG_POSITION(unk_0C, 0x0C);
|
||||
ASSERT_REG_POSITION(unk_6C, 0x6C);
|
||||
#undef ASSERT_REG_POSITION
|
||||
|
||||
class MiiSelector final : public Applet {
|
||||
public:
|
||||
MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) { }
|
||||
MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) {
|
||||
}
|
||||
|
||||
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
|
||||
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
|
||||
void Update() override;
|
||||
bool IsRunning() const override { return started; }
|
||||
bool IsRunning() const override {
|
||||
return started;
|
||||
}
|
||||
|
||||
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
|
||||
/// It holds the framebuffer info retrieved by the application with GSPGPU::ImportDisplayCaptureInfo
|
||||
/// It holds the framebuffer info retrieved by the application with
|
||||
/// GSPGPU::ImportDisplayCaptureInfo
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
|
||||
|
||||
/// Whether this applet is currently running instead of the host application or not.
|
||||
|
@ -78,6 +86,5 @@ public:
|
|||
|
||||
MiiConfig config;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include "core/hle/applets/swkbd.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/gsp_gpu.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/gsp_gpu.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
#include "video_core/video_core.h"
|
||||
|
@ -32,7 +32,8 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
|||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared
|
||||
// memory.
|
||||
// Create the SharedMemory that will hold the framebuffer data
|
||||
Service::APT::CaptureBufferInfo capture_info;
|
||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||
|
@ -43,9 +44,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
|||
// Allocate a heap block of the required size for this applet.
|
||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||
// Create a SharedMemory that directly points to this heap block.
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
"SoftwareKeyboard Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
||||
heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
|
@ -60,10 +61,12 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
|||
}
|
||||
|
||||
ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
|
||||
ASSERT_MSG(parameter.buffer.size() == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
|
||||
ASSERT_MSG(parameter.buffer.size() == sizeof(config),
|
||||
"The size of the parameter (SoftwareKeyboardConfig) is wrong");
|
||||
|
||||
memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
||||
text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
|
||||
text_memory =
|
||||
boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
|
||||
|
||||
// TODO(Subv): Verify if this is the correct behavior
|
||||
memset(text_memory->GetPointer(), 0, text_memory->size);
|
||||
|
@ -115,6 +118,5 @@ void SoftwareKeyboard::Finalize() {
|
|||
|
||||
started = false;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/applets/applet.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
@ -53,12 +53,15 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config
|
|||
|
||||
class SoftwareKeyboard final : public Applet {
|
||||
public:
|
||||
SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) { }
|
||||
SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {
|
||||
}
|
||||
|
||||
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
|
||||
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
|
||||
void Update() override;
|
||||
bool IsRunning() const override { return started; }
|
||||
bool IsRunning() const override {
|
||||
return started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a keyboard to the current bottom screen framebuffer.
|
||||
|
@ -72,7 +75,8 @@ public:
|
|||
void Finalize();
|
||||
|
||||
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
|
||||
/// It holds the framebuffer info retrieved by the application with GSPGPU::ImportDisplayCaptureInfo
|
||||
/// It holds the framebuffer info retrieved by the application with
|
||||
/// GSPGPU::ImportDisplayCaptureInfo
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
|
||||
|
||||
/// SharedMemory where the output text will be stored
|
||||
|
@ -84,6 +88,5 @@ public:
|
|||
/// Whether this applet is currently running instead of the host application or not.
|
||||
bool started;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include "core/hle/config_mem.h"
|
||||
#include <cstring>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -20,16 +20,16 @@
|
|||
namespace ConfigMem {
|
||||
|
||||
struct ConfigMemDef {
|
||||
u8 kernel_unk; // 0
|
||||
u8 kernel_version_rev; // 1
|
||||
u8 kernel_version_min; // 2
|
||||
u8 kernel_version_maj; // 3
|
||||
u8 kernel_unk; // 0
|
||||
u8 kernel_version_rev; // 1
|
||||
u8 kernel_version_min; // 2
|
||||
u8 kernel_version_maj; // 3
|
||||
u32_le update_flag; // 4
|
||||
u64_le ns_tid; // 8
|
||||
u32_le sys_core_ver; // 10
|
||||
u8 unit_info; // 14
|
||||
u8 boot_firm; // 15
|
||||
u8 prev_firm; // 16
|
||||
u8 unit_info; // 14
|
||||
u8 boot_firm; // 15
|
||||
u8 prev_firm; // 16
|
||||
INSERT_PADDING_BYTES(0x1); // 17
|
||||
u32_le ctr_sdk_ver; // 18
|
||||
INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C
|
||||
|
@ -39,15 +39,16 @@ struct ConfigMemDef {
|
|||
u32_le sys_mem_alloc; // 44
|
||||
u32_le base_mem_alloc; // 48
|
||||
INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C
|
||||
u8 firm_unk; // 60
|
||||
u8 firm_version_rev; // 61
|
||||
u8 firm_version_min; // 62
|
||||
u8 firm_version_maj; // 63
|
||||
u8 firm_unk; // 60
|
||||
u8 firm_version_rev; // 61
|
||||
u8 firm_version_min; // 62
|
||||
u8 firm_version_maj; // 63
|
||||
u32_le firm_sys_core_ver; // 64
|
||||
u32_le firm_ctr_sdk_ver; // 68
|
||||
INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C
|
||||
};
|
||||
static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong");
|
||||
static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE,
|
||||
"Config Memory structure size is wrong");
|
||||
|
||||
extern ConfigMemDef config_mem;
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
#include "common/common_types.h"
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace HLE {
|
||||
|
||||
#define PARAM(n) Core::g_app_core->GetReg(n)
|
||||
#define PARAM(n) Core::g_app_core->GetReg(n)
|
||||
|
||||
/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
|
||||
static const ResultCode RESULT_INVALID(0xDEADC0DE);
|
||||
|
@ -40,28 +40,33 @@ static inline void FuncReturn64(u64 res) {
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type ResultCode
|
||||
|
||||
template<ResultCode func(u32, u32, u32, u32)> void Wrap() {
|
||||
template <ResultCode func(u32, u32, u32, u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
|
||||
template <ResultCode func(u32*, u32, u32, u32, u32, u32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, s32, u32, u32, u32, s32)> void Wrap() {
|
||||
template <ResultCode func(u32*, s32, u32, u32, u32, s32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
|
||||
template <ResultCode func(s32*, u32*, s32, bool, s64)>
|
||||
void Wrap() {
|
||||
s32 param_1 = 0;
|
||||
s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
|
||||
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw;
|
||||
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)))
|
||||
.raw;
|
||||
|
||||
if (retval != RESULT_INVALID.raw) {
|
||||
Core::g_app_core->SetReg(1, (u32)param_1);
|
||||
|
@ -69,18 +74,22 @@ template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
|
|||
}
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw);
|
||||
template <ResultCode func(u32, u32, u32, u32, s64)>
|
||||
void Wrap() {
|
||||
FuncReturn(
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*)> void Wrap(){
|
||||
template <ResultCode func(u32*)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, s64)> void Wrap() {
|
||||
template <ResultCode func(u32, s64)>
|
||||
void Wrap() {
|
||||
s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw;
|
||||
|
||||
if (retval != RESULT_INVALID.raw) {
|
||||
|
@ -88,7 +97,8 @@ template<ResultCode func(u32, s64)> void Wrap() {
|
|||
}
|
||||
}
|
||||
|
||||
template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() {
|
||||
template <ResultCode func(MemoryInfo*, PageInfo*, u32)>
|
||||
void Wrap() {
|
||||
MemoryInfo memory_info = {};
|
||||
PageInfo page_info = {};
|
||||
u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
|
||||
|
@ -100,7 +110,8 @@ template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() {
|
|||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() {
|
||||
template <ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)>
|
||||
void Wrap() {
|
||||
MemoryInfo memory_info = {};
|
||||
PageInfo page_info = {};
|
||||
u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw;
|
||||
|
@ -112,55 +123,65 @@ template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() {
|
|||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s32*, u32)> void Wrap(){
|
||||
template <ResultCode func(s32*, u32)>
|
||||
void Wrap() {
|
||||
s32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, s32)> void Wrap() {
|
||||
template <ResultCode func(u32, s32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, u32)> void Wrap(){
|
||||
template <ResultCode func(u32*, u32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32)> void Wrap() {
|
||||
template <ResultCode func(u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(s64*, u32, u32*, u32)> void Wrap(){
|
||||
FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)),
|
||||
(s32)PARAM(3)).raw);
|
||||
template <ResultCode func(s64*, u32, u32*, u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1),
|
||||
(u32*)Memory::GetPointer(PARAM(2)), (s32)PARAM(3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, const char*)> void Wrap() {
|
||||
template <ResultCode func(u32*, const char*)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, (char*)Memory::GetPointer(PARAM(1))).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, s32, s32)> void Wrap() {
|
||||
template <ResultCode func(u32*, s32, s32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s32*, u32, s32)> void Wrap() {
|
||||
template <ResultCode func(s32*, u32, s32)>
|
||||
void Wrap() {
|
||||
s32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s64*, u32, s32)> void Wrap() {
|
||||
template <ResultCode func(s64*, u32, s32)>
|
||||
void Wrap() {
|
||||
s64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, (u32)param_1);
|
||||
|
@ -168,7 +189,8 @@ template<ResultCode func(s64*, u32, s32)> void Wrap() {
|
|||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
|
||||
template <ResultCode func(u32*, u32, u32, u32, u32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
// The last parameter is passed in R0 instead of R4
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw;
|
||||
|
@ -176,13 +198,15 @@ template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
|
|||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, s64, s64)> void Wrap() {
|
||||
template <ResultCode func(u32, s64, s64)>
|
||||
void Wrap() {
|
||||
s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2);
|
||||
s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1);
|
||||
FuncReturn(func(PARAM(0), param1, param2).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(s64*, Handle, u32)> void Wrap() {
|
||||
template <ResultCode func(s64*, Handle, u32)>
|
||||
void Wrap() {
|
||||
s64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, (u32)param_1);
|
||||
|
@ -190,14 +214,18 @@ template<ResultCode func(s64*, Handle, u32)> void Wrap() {
|
|||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(Handle, u32)> void Wrap() {
|
||||
template <ResultCode func(Handle, u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(Handle*, Handle*, const char*, u32)> void Wrap() {
|
||||
template <ResultCode func(Handle*, Handle*, const char*, u32)>
|
||||
void Wrap() {
|
||||
Handle param_1 = 0;
|
||||
Handle param_2 = 0;
|
||||
u32 retval = func(¶m_1, ¶m_2, reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3)).raw;
|
||||
u32 retval = func(¶m_1, ¶m_2,
|
||||
reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3))
|
||||
.raw;
|
||||
// The first out parameter is moved into R2 and the second is moved into R1.
|
||||
Core::g_app_core->SetReg(1, param_2);
|
||||
Core::g_app_core->SetReg(2, param_1);
|
||||
|
@ -207,29 +235,34 @@ template<ResultCode func(Handle*, Handle*, const char*, u32)> void Wrap() {
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type u32
|
||||
|
||||
template<u32 func()> void Wrap() {
|
||||
template <u32 func()>
|
||||
void Wrap() {
|
||||
FuncReturn(func());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type s64
|
||||
|
||||
template<s64 func()> void Wrap() {
|
||||
template <s64 func()>
|
||||
void Wrap() {
|
||||
FuncReturn64(func());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Function wrappers that return type void
|
||||
|
||||
template<void func(s64)> void Wrap() {
|
||||
template <void func(s64)>
|
||||
void Wrap() {
|
||||
func(((s64)PARAM(1) << 32) | PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(const char*)> void Wrap() {
|
||||
template <void func(const char*)>
|
||||
void Wrap() {
|
||||
func((char*)Memory::GetPointer(PARAM(0)));
|
||||
}
|
||||
|
||||
template<void func(u8)> void Wrap() {
|
||||
template <void func(u8)>
|
||||
void Wrap() {
|
||||
func((u8)PARAM(0));
|
||||
}
|
||||
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
namespace {
|
||||
|
||||
bool reschedule; ///< If true, immediately reschedules the CPU to a new thread
|
||||
|
||||
}
|
||||
|
||||
namespace HLE {
|
||||
|
||||
void Reschedule(const char *reason) {
|
||||
DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
|
||||
void Reschedule(const char* reason) {
|
||||
DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256,
|
||||
"Reschedule: Invalid or too long reason.");
|
||||
|
||||
// TODO(bunnei): It seems that games depend on some CPU execution time elapsing during HLE
|
||||
// routines. This simulates that time by artificially advancing the number of CPU "ticks".
|
||||
|
|
|
@ -13,7 +13,7 @@ const Handle INVALID_HANDLE = 0;
|
|||
|
||||
namespace HLE {
|
||||
|
||||
void Reschedule(const char *reason);
|
||||
void Reschedule(const char* reason);
|
||||
bool IsReschedulePending();
|
||||
void DoneRescheduling();
|
||||
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
AddressArbiter::AddressArbiter() {}
|
||||
AddressArbiter::~AddressArbiter() {}
|
||||
AddressArbiter::AddressArbiter() {
|
||||
}
|
||||
AddressArbiter::~AddressArbiter() {
|
||||
}
|
||||
|
||||
SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) {
|
||||
SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter);
|
||||
|
@ -28,7 +30,7 @@ SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) {
|
|||
}
|
||||
|
||||
ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value,
|
||||
u64 nanoseconds) {
|
||||
u64 nanoseconds) {
|
||||
switch (type) {
|
||||
|
||||
// Signal thread(s) waiting for arbitrate address...
|
||||
|
@ -38,7 +40,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
|||
ArbitrateAllThreads(address);
|
||||
} else {
|
||||
// Resume first N threads
|
||||
for(int i = 0; i < value; i++)
|
||||
for (int i = 0; i < value; i++)
|
||||
ArbitrateHighestPriorityThread(address);
|
||||
}
|
||||
break;
|
||||
|
@ -55,8 +57,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
|||
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
||||
}
|
||||
break;
|
||||
case ArbitrationType::DecrementAndWaitIfLessThan:
|
||||
{
|
||||
case ArbitrationType::DecrementAndWaitIfLessThan: {
|
||||
s32 memory_value = Memory::Read32(address);
|
||||
if (memory_value < value) {
|
||||
// Only change the memory value if the thread should wait
|
||||
|
@ -65,8 +66,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout:
|
||||
{
|
||||
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: {
|
||||
s32 memory_value = Memory::Read32(address);
|
||||
if (memory_value < value) {
|
||||
// Only change the memory value if the thread should wait
|
||||
|
@ -79,17 +79,19 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
|||
|
||||
default:
|
||||
LOG_ERROR(Kernel, "unknown type=%d", type);
|
||||
return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
HLE::Reschedule(__func__);
|
||||
|
||||
// The calls that use a timeout seem to always return a Timeout error even if they did not put the thread to sleep
|
||||
// The calls that use a timeout seem to always return a Timeout error even if they did not put
|
||||
// the thread to sleep
|
||||
if (type == ArbitrationType::WaitIfLessThanWithTimeout ||
|
||||
type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) {
|
||||
|
||||
return ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
|
||||
ErrorSummary::StatusChanged, ErrorLevel::Info);
|
||||
return ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged,
|
||||
ErrorLevel::Info);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -36,13 +36,19 @@ public:
|
|||
*/
|
||||
static SharedPtr<AddressArbiter> Create(std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Arbiter"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Arbiter";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::AddressArbiter;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
std::string name; ///< Name of address arbiter object (optional)
|
||||
std::string name; ///< Name of address arbiter object (optional)
|
||||
|
||||
ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds);
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
ClientPort::ClientPort() {}
|
||||
ClientPort::~ClientPort() {}
|
||||
ClientPort::ClientPort() {
|
||||
}
|
||||
ClientPort::~ClientPort() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -17,16 +17,22 @@ class ServerPort;
|
|||
class ClientPort : public Object {
|
||||
public:
|
||||
friend class ServerPort;
|
||||
std::string GetTypeName() const override { return "ClientPort"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "ClientPort";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ClientPort;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
||||
u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
|
||||
u32 active_sessions; ///< Number of currently open sessions to this port
|
||||
std::string name; ///< Name of client port (optional)
|
||||
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
||||
u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
|
||||
u32 active_sessions; ///< Number of currently open sessions to this port
|
||||
std::string name; ///< Name of client port (optional)
|
||||
|
||||
protected:
|
||||
ClientPort();
|
||||
|
|
|
@ -2,20 +2,22 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Event::Event() {}
|
||||
Event::~Event() {}
|
||||
Event::Event() {
|
||||
}
|
||||
Event::~Event() {
|
||||
}
|
||||
|
||||
SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
|
||||
SharedPtr<Event> evt(new Event);
|
||||
|
|
|
@ -16,7 +16,6 @@ enum class ResetType {
|
|||
Pulse,
|
||||
};
|
||||
|
||||
|
||||
class Event final : public WaitObject {
|
||||
public:
|
||||
/**
|
||||
|
@ -26,16 +25,22 @@ public:
|
|||
*/
|
||||
static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Event"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Event";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Event;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
ResetType reset_type; ///< Current ResetType
|
||||
ResetType reset_type; ///< Current ResetType
|
||||
|
||||
bool signaled; ///< Whether the event has already been signaled
|
||||
std::string name; ///< Name of event (optional)
|
||||
bool signaled; ///< Whether the event has already been signaled
|
||||
std::string name; ///< Name of event (optional)
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
|
|
@ -61,7 +61,8 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
|
|||
|
||||
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
|
||||
// CTR-OS doesn't use generation 0, so skip straight to 1.
|
||||
if (next_generation >= (1 << 15)) next_generation = 1;
|
||||
if (next_generation >= (1 << 15))
|
||||
next_generation = 1;
|
||||
|
||||
generations[slot] = generation;
|
||||
objects[slot] = std::move(obj);
|
||||
|
|
|
@ -23,48 +23,55 @@ class Thread;
|
|||
|
||||
// TODO: Verify code
|
||||
const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
|
||||
ErrorSummary::OutOfResource, ErrorLevel::Temporary);
|
||||
ErrorSummary::OutOfResource, ErrorLevel::Temporary);
|
||||
// TOOD: Verify code
|
||||
const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
|
||||
enum KernelHandle : Handle {
|
||||
CurrentThread = 0xFFFF8000,
|
||||
CurrentProcess = 0xFFFF8001,
|
||||
CurrentThread = 0xFFFF8000,
|
||||
CurrentProcess = 0xFFFF8001,
|
||||
};
|
||||
|
||||
enum class HandleType : u32 {
|
||||
Unknown = 0,
|
||||
Unknown = 0,
|
||||
|
||||
Session = 2,
|
||||
Event = 3,
|
||||
Mutex = 4,
|
||||
SharedMemory = 5,
|
||||
Redirection = 6,
|
||||
Thread = 7,
|
||||
Process = 8,
|
||||
AddressArbiter = 9,
|
||||
Semaphore = 10,
|
||||
Timer = 11,
|
||||
ResourceLimit = 12,
|
||||
CodeSet = 13,
|
||||
ClientPort = 14,
|
||||
ServerPort = 15,
|
||||
Session = 2,
|
||||
Event = 3,
|
||||
Mutex = 4,
|
||||
SharedMemory = 5,
|
||||
Redirection = 6,
|
||||
Thread = 7,
|
||||
Process = 8,
|
||||
AddressArbiter = 9,
|
||||
Semaphore = 10,
|
||||
Timer = 11,
|
||||
ResourceLimit = 12,
|
||||
CodeSet = 13,
|
||||
ClientPort = 14,
|
||||
ServerPort = 15,
|
||||
};
|
||||
|
||||
enum {
|
||||
DEFAULT_STACK_SIZE = 0x4000,
|
||||
DEFAULT_STACK_SIZE = 0x4000,
|
||||
};
|
||||
|
||||
class Object : NonCopyable {
|
||||
public:
|
||||
virtual ~Object() {}
|
||||
virtual ~Object() {
|
||||
}
|
||||
|
||||
/// Returns a unique identifier for the object. For debugging purposes only.
|
||||
unsigned int GetObjectId() const { return object_id; }
|
||||
unsigned int GetObjectId() const {
|
||||
return object_id;
|
||||
}
|
||||
|
||||
virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
|
||||
virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
|
||||
virtual std::string GetTypeName() const {
|
||||
return "[BAD KERNEL OBJECT TYPE]";
|
||||
}
|
||||
virtual std::string GetName() const {
|
||||
return "[UNKNOWN KERNEL OBJECT]";
|
||||
}
|
||||
virtual Kernel::HandleType GetHandleType() const = 0;
|
||||
|
||||
/**
|
||||
|
@ -122,7 +129,6 @@ using SharedPtr = boost::intrusive_ptr<T>;
|
|||
/// Class that represents a Kernel object that a thread can be waiting on
|
||||
class WaitObject : public Object {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Check if the current thread should wait until the object is available
|
||||
* @return True if the current thread should wait due to this object being unavailable
|
||||
|
@ -247,8 +253,12 @@ private:
|
|||
*/
|
||||
static const size_t MAX_COUNT = 4096;
|
||||
|
||||
static u16 GetSlot(Handle handle) { return handle >> 15; }
|
||||
static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; }
|
||||
static u16 GetSlot(Handle handle) {
|
||||
return handle >> 15;
|
||||
}
|
||||
static u16 GetGeneration(Handle handle) {
|
||||
return handle & 0x7FFF;
|
||||
}
|
||||
|
||||
/// Stores the Object referenced by the handle or null if the slot is empty.
|
||||
std::array<SharedPtr<Object>, MAX_COUNT> objects;
|
||||
|
|
|
@ -31,7 +31,7 @@ static MemoryRegionInfo memory_regions[3];
|
|||
static const u32 memory_region_sizes[8][3] = {
|
||||
// Old 3DS layouts
|
||||
{0x04000000, 0x02C00000, 0x01400000}, // 0
|
||||
{ /* This appears to be unused. */ }, // 1
|
||||
{/* This appears to be unused. */}, // 1
|
||||
{0x06000000, 0x00C00000, 0x01400000}, // 2
|
||||
{0x05000000, 0x01C00000, 0x01400000}, // 3
|
||||
{0x04800000, 0x02400000, 0x01400000}, // 4
|
||||
|
@ -95,7 +95,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
|
|||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Memory {
|
||||
|
@ -110,9 +109,8 @@ struct MemoryArea {
|
|||
|
||||
// We don't declare the IO regions in here since its handled by other means.
|
||||
static MemoryArea memory_areas[] = {
|
||||
{VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
|
||||
{VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void Init() {
|
||||
|
@ -125,15 +123,21 @@ void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
|
|||
|
||||
for (MemoryArea& area : memory_areas) {
|
||||
auto block = std::make_shared<std::vector<u8>>(area.size);
|
||||
address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
|
||||
address_space
|
||||
.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private)
|
||||
.Unwrap();
|
||||
}
|
||||
|
||||
auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
|
||||
(u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
|
||||
auto cfg_mem_vma = address_space
|
||||
.MapBackingMemory(CONFIG_MEMORY_VADDR, (u8*)&ConfigMem::config_mem,
|
||||
CONFIG_MEMORY_SIZE, MemoryState::Shared)
|
||||
.MoveFrom();
|
||||
address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
|
||||
|
||||
auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
|
||||
(u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
|
||||
auto shared_page_vma = address_space
|
||||
.MapBackingMemory(SHARED_PAGE_VADDR, (u8*)&SharedPage::shared_page,
|
||||
SHARED_PAGE_SIZE, MemoryState::Shared)
|
||||
.MoveFrom();
|
||||
address_space.Reprotect(shared_page_vma, VMAPermission::Read);
|
||||
|
||||
AudioCore::AddAddressSpace(address_space);
|
||||
|
|
|
@ -25,7 +25,6 @@ struct MemoryRegionInfo {
|
|||
void MemoryInit(u32 mem_type);
|
||||
void MemoryShutdown();
|
||||
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
|
||||
|
||||
}
|
||||
|
||||
namespace Memory {
|
||||
|
|
|
@ -33,8 +33,10 @@ void ReleaseThreadMutexes(Thread* thread) {
|
|||
thread->held_mutexes.clear();
|
||||
}
|
||||
|
||||
Mutex::Mutex() {}
|
||||
Mutex::~Mutex() {}
|
||||
Mutex::Mutex() {
|
||||
}
|
||||
Mutex::~Mutex() {
|
||||
}
|
||||
|
||||
SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
|
||||
SharedPtr<Mutex> mutex(new Mutex);
|
||||
|
|
|
@ -24,15 +24,21 @@ public:
|
|||
*/
|
||||
static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Mutex"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Mutex";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Mutex;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
int lock_count; ///< Number of times the mutex has been acquired
|
||||
std::string name; ///< Name of mutex (optional)
|
||||
SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
|
||||
int lock_count; ///< Number of times the mutex has been acquired
|
||||
std::string name; ///< Name of mutex (optional)
|
||||
SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
|
|
@ -26,8 +26,10 @@ SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) {
|
|||
return codeset;
|
||||
}
|
||||
|
||||
CodeSet::CodeSet() {}
|
||||
CodeSet::~CodeSet() {}
|
||||
CodeSet::CodeSet() {
|
||||
}
|
||||
CodeSet::~CodeSet() {
|
||||
}
|
||||
|
||||
u32 Process::next_process_id;
|
||||
|
||||
|
@ -60,7 +62,8 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
|
|||
|
||||
while (bits && index < svc_access_mask.size()) {
|
||||
svc_access_mask.set(index, bits & 1);
|
||||
++index; bits >>= 1;
|
||||
++index;
|
||||
bits >>= 1;
|
||||
}
|
||||
} else if ((type & 0xFF0) == 0xFE0) { // 0x00FF
|
||||
// Handle table size
|
||||
|
@ -70,11 +73,11 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
|
|||
flags.raw = descriptor & 0xFFFF;
|
||||
} else if ((type & 0xFFE) == 0xFF8) { // 0x001F
|
||||
// Mapped memory range
|
||||
if (i+1 >= len || ((kernel_caps[i+1] >> 20) & 0xFFE) != 0xFF8) {
|
||||
if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) {
|
||||
LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
|
||||
continue;
|
||||
}
|
||||
u32 end_desc = kernel_caps[i+1];
|
||||
u32 end_desc = kernel_caps[i + 1];
|
||||
++i; // Skip over the second descriptor on the next iteration
|
||||
|
||||
AddressMapping mapping;
|
||||
|
@ -107,23 +110,28 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
|
|||
void Process::Run(s32 main_thread_priority, u32 stack_size) {
|
||||
memory_region = GetMemoryRegion(flags.memory_region);
|
||||
|
||||
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) {
|
||||
auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory,
|
||||
segment.offset, segment.size, memory_state).Unwrap();
|
||||
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
|
||||
MemoryState memory_state) {
|
||||
auto vma = vm_manager
|
||||
.MapMemoryBlock(segment.addr, codeset->memory, segment.offset, segment.size,
|
||||
memory_state)
|
||||
.Unwrap();
|
||||
vm_manager.Reprotect(vma, permissions);
|
||||
misc_memory_used += segment.size;
|
||||
memory_region->used += segment.size;
|
||||
};
|
||||
|
||||
// Map CodeSet segments
|
||||
MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
|
||||
MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
|
||||
MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
|
||||
MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
|
||||
MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
|
||||
MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
|
||||
|
||||
// Allocate and map stack
|
||||
vm_manager.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,
|
||||
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked
|
||||
).Unwrap();
|
||||
vm_manager
|
||||
.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,
|
||||
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
|
||||
MemoryState::Locked)
|
||||
.Unwrap();
|
||||
misc_memory_used += stack_size;
|
||||
memory_region->used += stack_size;
|
||||
|
||||
|
@ -143,7 +151,8 @@ VAddr Process::GetLinearHeapLimit() const {
|
|||
}
|
||||
|
||||
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
|
||||
target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
|
@ -166,7 +175,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
|
|||
}
|
||||
ASSERT(heap_end - heap_start == heap_memory->size());
|
||||
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, size, MemoryState::Private));
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
|
||||
size, MemoryState::Private));
|
||||
vm_manager.Reprotect(vma, perms);
|
||||
|
||||
heap_used += size;
|
||||
|
@ -176,7 +186,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
|
|||
}
|
||||
|
||||
ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
|
||||
target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
|
@ -185,7 +196,8 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
|
|||
}
|
||||
|
||||
ResultCode result = vm_manager.UnmapRange(target, size);
|
||||
if (result.IsError()) return result;
|
||||
if (result.IsError())
|
||||
return result;
|
||||
|
||||
heap_used -= size;
|
||||
memory_region->used -= size;
|
||||
|
@ -203,8 +215,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
|
|||
target = heap_end;
|
||||
}
|
||||
|
||||
if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
|
||||
target > heap_end || target + size < target) {
|
||||
if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || target > heap_end ||
|
||||
target + size < target) {
|
||||
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
@ -220,7 +232,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
|
|||
// TODO(yuriks): As is, this lets processes map memory allocated by other processes from the
|
||||
// same region. It is unknown if or how the 3DS kernel checks against this.
|
||||
size_t offset = target - GetLinearHeapBase();
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous));
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size,
|
||||
MemoryState::Continuous));
|
||||
vm_manager.Reprotect(vma, perms);
|
||||
|
||||
linear_heap_used += size;
|
||||
|
@ -248,7 +261,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
|
|||
}
|
||||
|
||||
ResultCode result = vm_manager.UnmapRange(target, size);
|
||||
if (result.IsError()) return result;
|
||||
if (result.IsError())
|
||||
return result;
|
||||
|
||||
linear_heap_used -= size;
|
||||
memory_region->used -= size;
|
||||
|
@ -268,9 +282,10 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
|
|||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
Kernel::Process::Process() {}
|
||||
Kernel::Process::~Process() {}
|
||||
Kernel::Process::Process() {
|
||||
}
|
||||
Kernel::Process::~Process() {
|
||||
}
|
||||
|
||||
SharedPtr<Process> g_current_process;
|
||||
|
||||
}
|
||||
|
|
|
@ -36,15 +36,18 @@ enum class MemoryRegion : u16 {
|
|||
union ProcessFlags {
|
||||
u16 raw;
|
||||
|
||||
BitField< 0, 1, u16> allow_debug; ///< Allows other processes to attach to and debug this process.
|
||||
BitField< 1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they don't have allow_debug set.
|
||||
BitField< 2, 1, u16> allow_nonalphanum;
|
||||
BitField< 3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions.
|
||||
BitField< 4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24.
|
||||
BitField< 5, 1, u16> allow_main_args;
|
||||
BitField< 6, 1, u16> shared_device_mem;
|
||||
BitField< 7, 1, u16> runnable_on_sleep;
|
||||
BitField< 8, 4, MemoryRegion> memory_region; ///< Default region for memory allocations for this process
|
||||
BitField<0, 1, u16>
|
||||
allow_debug; ///< Allows other processes to attach to and debug this process.
|
||||
BitField<1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they
|
||||
/// don't have allow_debug set.
|
||||
BitField<2, 1, u16> allow_nonalphanum;
|
||||
BitField<3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions.
|
||||
BitField<4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24.
|
||||
BitField<5, 1, u16> allow_main_args;
|
||||
BitField<6, 1, u16> shared_device_mem;
|
||||
BitField<7, 1, u16> runnable_on_sleep;
|
||||
BitField<8, 4, MemoryRegion>
|
||||
memory_region; ///< Default region for memory allocations for this process
|
||||
BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
|
||||
};
|
||||
|
||||
|
@ -54,11 +57,17 @@ struct MemoryRegionInfo;
|
|||
struct CodeSet final : public Object {
|
||||
static SharedPtr<CodeSet> Create(std::string name, u64 program_id);
|
||||
|
||||
std::string GetTypeName() const override { return "CodeSet"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "CodeSet";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::CodeSet;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/// Name of the process
|
||||
std::string name;
|
||||
|
@ -85,11 +94,17 @@ class Process final : public Object {
|
|||
public:
|
||||
static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set);
|
||||
|
||||
std::string GetTypeName() const override { return "Process"; }
|
||||
std::string GetName() const override { return codeset->name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Process";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return codeset->name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Process;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
static u32 next_process_id;
|
||||
|
||||
|
@ -124,7 +139,6 @@ public:
|
|||
*/
|
||||
void Run(s32 main_thread_priority, u32 stack_size);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory Management
|
||||
|
||||
|
@ -144,7 +158,8 @@ public:
|
|||
|
||||
/// The Thread Local Storage area is allocated as processes create threads,
|
||||
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
|
||||
/// holds the TLS for a specific thread. This vector contains which parts are in use for each page as a bitmask.
|
||||
/// holds the TLS for a specific thread. This vector contains which parts are in use for each
|
||||
/// page as a bitmask.
|
||||
/// This vector will grow as more pages are allocated for new threads.
|
||||
std::vector<std::bitset<8>> tls_slots;
|
||||
|
||||
|
@ -164,5 +179,4 @@ private:
|
|||
};
|
||||
|
||||
extern SharedPtr<Process> g_current_process;
|
||||
|
||||
}
|
||||
|
|
|
@ -12,8 +12,10 @@ namespace Kernel {
|
|||
|
||||
static SharedPtr<ResourceLimit> resource_limits[4];
|
||||
|
||||
ResourceLimit::ResourceLimit() {}
|
||||
ResourceLimit::~ResourceLimit() {}
|
||||
ResourceLimit::ResourceLimit() {
|
||||
}
|
||||
ResourceLimit::~ResourceLimit() {
|
||||
}
|
||||
|
||||
SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) {
|
||||
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit);
|
||||
|
@ -23,70 +25,69 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) {
|
|||
}
|
||||
|
||||
SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) {
|
||||
switch (category)
|
||||
{
|
||||
case ResourceLimitCategory::APPLICATION:
|
||||
case ResourceLimitCategory::SYS_APPLET:
|
||||
case ResourceLimitCategory::LIB_APPLET:
|
||||
case ResourceLimitCategory::OTHER:
|
||||
return resource_limits[static_cast<u8>(category)];
|
||||
default:
|
||||
LOG_CRITICAL(Kernel, "Unknown resource limit category");
|
||||
UNREACHABLE();
|
||||
switch (category) {
|
||||
case ResourceLimitCategory::APPLICATION:
|
||||
case ResourceLimitCategory::SYS_APPLET:
|
||||
case ResourceLimitCategory::LIB_APPLET:
|
||||
case ResourceLimitCategory::OTHER:
|
||||
return resource_limits[static_cast<u8>(category)];
|
||||
default:
|
||||
LOG_CRITICAL(Kernel, "Unknown resource limit category");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const {
|
||||
switch (resource) {
|
||||
case COMMIT:
|
||||
return current_commit;
|
||||
case THREAD:
|
||||
return current_threads;
|
||||
case EVENT:
|
||||
return current_events;
|
||||
case MUTEX:
|
||||
return current_mutexes;
|
||||
case SEMAPHORE:
|
||||
return current_semaphores;
|
||||
case TIMER:
|
||||
return current_timers;
|
||||
case SHARED_MEMORY:
|
||||
return current_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return current_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return current_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
case COMMIT:
|
||||
return current_commit;
|
||||
case THREAD:
|
||||
return current_threads;
|
||||
case EVENT:
|
||||
return current_events;
|
||||
case MUTEX:
|
||||
return current_mutexes;
|
||||
case SEMAPHORE:
|
||||
return current_semaphores;
|
||||
case TIMER:
|
||||
return current_timers;
|
||||
case SHARED_MEMORY:
|
||||
return current_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return current_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return current_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
s32 ResourceLimit::GetMaxResourceValue(u32 resource) const {
|
||||
switch (resource) {
|
||||
case COMMIT:
|
||||
return max_commit;
|
||||
case THREAD:
|
||||
return max_threads;
|
||||
case EVENT:
|
||||
return max_events;
|
||||
case MUTEX:
|
||||
return max_mutexes;
|
||||
case SEMAPHORE:
|
||||
return max_semaphores;
|
||||
case TIMER:
|
||||
return max_timers;
|
||||
case SHARED_MEMORY:
|
||||
return max_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return max_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return max_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
case COMMIT:
|
||||
return max_commit;
|
||||
case THREAD:
|
||||
return max_threads;
|
||||
case EVENT:
|
||||
return max_events;
|
||||
case MUTEX:
|
||||
return max_mutexes;
|
||||
case SEMAPHORE:
|
||||
return max_semaphores;
|
||||
case TIMER:
|
||||
return max_timers;
|
||||
case SHARED_MEMORY:
|
||||
return max_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return max_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return max_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +151,6 @@ void ResourceLimitsInit() {
|
|||
}
|
||||
|
||||
void ResourceLimitsShutdown() {
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -12,22 +12,22 @@ namespace Kernel {
|
|||
|
||||
enum class ResourceLimitCategory : u8 {
|
||||
APPLICATION = 0,
|
||||
SYS_APPLET = 1,
|
||||
LIB_APPLET = 2,
|
||||
OTHER = 3
|
||||
SYS_APPLET = 1,
|
||||
LIB_APPLET = 2,
|
||||
OTHER = 3
|
||||
};
|
||||
|
||||
enum ResourceTypes {
|
||||
PRIORITY = 0,
|
||||
COMMIT = 1,
|
||||
THREAD = 2,
|
||||
EVENT = 3,
|
||||
MUTEX = 4,
|
||||
SEMAPHORE = 5,
|
||||
TIMER = 6,
|
||||
SHARED_MEMORY = 7,
|
||||
ADDRESS_ARBITER = 8,
|
||||
CPU_TIME = 9,
|
||||
PRIORITY = 0,
|
||||
COMMIT = 1,
|
||||
THREAD = 2,
|
||||
EVENT = 3,
|
||||
MUTEX = 4,
|
||||
SEMAPHORE = 5,
|
||||
TIMER = 6,
|
||||
SHARED_MEMORY = 7,
|
||||
ADDRESS_ARBITER = 8,
|
||||
CPU_TIME = 9,
|
||||
};
|
||||
|
||||
class ResourceLimit final : public Object {
|
||||
|
@ -44,11 +44,17 @@ public:
|
|||
*/
|
||||
static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category);
|
||||
|
||||
std::string GetTypeName() const override { return "ResourceLimit"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "ResourceLimit";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current value for the specified resource.
|
||||
|
@ -85,10 +91,12 @@ public:
|
|||
/// Max CPU time that the processes in this category can utilize
|
||||
s32 max_cpu_time = 0;
|
||||
|
||||
// TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
|
||||
// TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind
|
||||
// that
|
||||
// APPLICATION resource limits should not be affected by the objects created by service modules.
|
||||
// Currently we have no way of distinguishing if a Create was called by the running application,
|
||||
// or by a service module. Approach this once we have separated the service modules into their own processes
|
||||
// or by a service module. Approach this once we have separated the service modules into their
|
||||
// own processes
|
||||
|
||||
/// Current memory that the processes in this category are using
|
||||
s32 current_commit = 0;
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
Semaphore::Semaphore() {}
|
||||
Semaphore::~Semaphore() {}
|
||||
Semaphore::Semaphore() {
|
||||
}
|
||||
Semaphore::~Semaphore() {
|
||||
}
|
||||
|
||||
ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count,
|
||||
std::string name) {
|
||||
std::string name) {
|
||||
|
||||
if (initial_count > max_count)
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
|
||||
|
|
|
@ -23,17 +23,23 @@ public:
|
|||
* @return The created semaphore
|
||||
*/
|
||||
static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count,
|
||||
std::string name = "Unknown");
|
||||
std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Semaphore"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Semaphore";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Semaphore;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
|
||||
s32 available_count; ///< Number of free slots left in the semaphore
|
||||
std::string name; ///< Name of semaphore (optional)
|
||||
s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
|
||||
s32 available_count; ///< Number of free slots left in the semaphore
|
||||
std::string name; ///< Name of semaphore (optional)
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
ServerPort::ServerPort() {}
|
||||
ServerPort::~ServerPort() {}
|
||||
ServerPort::ServerPort() {
|
||||
}
|
||||
ServerPort::~ServerPort() {
|
||||
}
|
||||
|
||||
bool ServerPort::ShouldWait() {
|
||||
// If there are no pending sessions, we wait until a new one is added.
|
||||
|
@ -25,7 +27,8 @@ void ServerPort::Acquire() {
|
|||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
||||
}
|
||||
|
||||
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(u32 max_sessions, std::string name) {
|
||||
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>>
|
||||
ServerPort::CreatePortPair(u32 max_sessions, std::string name) {
|
||||
SharedPtr<ServerPort> server_port(new ServerPort);
|
||||
SharedPtr<ClientPort> client_port(new ClientPort);
|
||||
|
||||
|
|
|
@ -23,17 +23,25 @@ public:
|
|||
* @param name Optional name of the ports
|
||||
* @return The created port tuple
|
||||
*/
|
||||
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(u32 max_sessions, std::string name = "UnknownPort");
|
||||
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>>
|
||||
CreatePortPair(u32 max_sessions, std::string name = "UnknownPort");
|
||||
|
||||
std::string GetTypeName() const override { return "ServerPort"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "ServerPort";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ServerPort;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
std::string name; ///< Name of port (optional)
|
||||
std::string name; ///< Name of port (optional)
|
||||
|
||||
std::vector<SharedPtr<WaitObject>> pending_sessions; ///< ServerSessions waiting to be accepted by the port
|
||||
std::vector<SharedPtr<WaitObject>>
|
||||
pending_sessions; ///< ServerSessions waiting to be accepted by the port
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
Session::Session() {}
|
||||
Session::~Session() {}
|
||||
|
||||
Session::Session() {
|
||||
}
|
||||
Session::~Session() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,13 @@ namespace IPC {
|
|||
enum DescriptorType : u32 {
|
||||
// Buffer related desciptors types (mask : 0x0F)
|
||||
StaticBuffer = 0x02,
|
||||
PXIBuffer = 0x04,
|
||||
PXIBuffer = 0x04,
|
||||
MappedBuffer = 0x08,
|
||||
// Handle related descriptors types (mask : 0x30, but need to check for buffer related descriptors first )
|
||||
CopyHandle = 0x00,
|
||||
MoveHandle = 0x10,
|
||||
CallingPid = 0x20,
|
||||
// Handle related descriptors types (mask : 0x30, but need to check for buffer related
|
||||
// descriptors first )
|
||||
CopyHandle = 0x00,
|
||||
MoveHandle = 0x10,
|
||||
CallingPid = 0x20,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -34,24 +35,28 @@ enum DescriptorType : u32 {
|
|||
* @param translate_params_size Size of the translate parameters in words. Up to 63.
|
||||
* @return The created IPC header.
|
||||
*
|
||||
* Normal parameters are sent directly to the process while the translate parameters might go through modifications and checks by the kernel.
|
||||
* Normal parameters are sent directly to the process while the translate parameters might go
|
||||
* through modifications and checks by the kernel.
|
||||
* The translate parameters are described by headers generated with the IPC::*Desc functions.
|
||||
*
|
||||
* @note While #normal_params is equivalent to the number of normal parameters, #translate_params_size includes the size occupied by the translate parameters headers.
|
||||
* @note While #normal_params is equivalent to the number of normal parameters,
|
||||
* #translate_params_size includes the size occupied by the translate parameters headers.
|
||||
*/
|
||||
constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, unsigned int translate_params_size) {
|
||||
return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | (u32(translate_params_size) & 0x3F);
|
||||
constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params,
|
||||
unsigned int translate_params_size) {
|
||||
return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) |
|
||||
(u32(translate_params_size) & 0x3F);
|
||||
}
|
||||
|
||||
union Header {
|
||||
u32 raw;
|
||||
BitField< 0, 6, u32> translate_params_size;
|
||||
BitField< 6, 6, u32> normal_params;
|
||||
BitField<0, 6, u32> translate_params_size;
|
||||
BitField<6, 6, u32> normal_params;
|
||||
BitField<16, 16, u32> command_id;
|
||||
};
|
||||
|
||||
inline Header ParseHeader(u32 header) {
|
||||
return{ header };
|
||||
return {header};
|
||||
}
|
||||
|
||||
constexpr u32 MoveHandleDesc(u32 num_handles = 1) {
|
||||
|
@ -80,27 +85,29 @@ constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) {
|
|||
|
||||
union StaticBufferDescInfo {
|
||||
u32 raw;
|
||||
BitField< 10, 4, u32> buffer_id;
|
||||
BitField< 14, 18, u32> size;
|
||||
BitField<10, 4, u32> buffer_id;
|
||||
BitField<14, 18, u32> size;
|
||||
};
|
||||
|
||||
inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) {
|
||||
return{ desc };
|
||||
return {desc};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a header describing a buffer to be sent over PXI.
|
||||
* @param size Size of the buffer. Max 0x00FFFFFF.
|
||||
* @param buffer_id The Id of the buffer. Max 0xF.
|
||||
* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have read-write access.
|
||||
* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have
|
||||
* read-write access.
|
||||
* @return The created PXI buffer header.
|
||||
*
|
||||
* The next value is a phys-address of a table located in the BASE memregion.
|
||||
*/
|
||||
inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) {
|
||||
u32 type = PXIBuffer;
|
||||
if (is_read_only) type |= 0x2;
|
||||
return type | (size << 8) | ((buffer_id & 0xF) << 4);
|
||||
if (is_read_only)
|
||||
type |= 0x2;
|
||||
return type | (size << 8) | ((buffer_id & 0xF) << 4);
|
||||
}
|
||||
|
||||
enum MappedBufferPermissions {
|
||||
|
@ -115,12 +122,12 @@ constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {
|
|||
|
||||
union MappedBufferDescInfo {
|
||||
u32 raw;
|
||||
BitField< 4, 28, u32> size;
|
||||
BitField< 1, 2, MappedBufferPermissions> perms;
|
||||
BitField<4, 28, u32> size;
|
||||
BitField<1, 2, MappedBufferPermissions> perms;
|
||||
};
|
||||
|
||||
inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) {
|
||||
return{ desc };
|
||||
return {desc};
|
||||
}
|
||||
|
||||
inline DescriptorType GetDescriptorType(u32 descriptor) {
|
||||
|
@ -153,7 +160,8 @@ static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of
|
|||
* @return Pointer to command buffer
|
||||
*/
|
||||
inline u32* GetCommandBuffer(const int offset = 0) {
|
||||
return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset);
|
||||
return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
|
||||
offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,10 +191,14 @@ public:
|
|||
Session();
|
||||
~Session() override;
|
||||
|
||||
std::string GetTypeName() const override { return "Session"; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Session";
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Session;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
|
||||
|
@ -205,5 +217,4 @@ public:
|
|||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -6,17 +6,21 @@
|
|||
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/memory.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
SharedMemory::SharedMemory() {}
|
||||
SharedMemory::~SharedMemory() {}
|
||||
SharedMemory::SharedMemory() {
|
||||
}
|
||||
SharedMemory::~SharedMemory() {
|
||||
}
|
||||
|
||||
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
|
||||
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address,
|
||||
MemoryRegion region, std::string name) {
|
||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
||||
|
||||
shared_memory->owner_process = owner_process;
|
||||
|
@ -31,7 +35,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
|||
MemoryRegionInfo* memory_region = GetMemoryRegion(region);
|
||||
auto& linheap_memory = memory_region->linear_heap_memory;
|
||||
|
||||
ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, "Not enough space in region to allocate shared memory!");
|
||||
ASSERT_MSG(linheap_memory->size() + size <= memory_region->size,
|
||||
"Not enough space in region to allocate shared memory!");
|
||||
|
||||
shared_memory->backing_block = linheap_memory;
|
||||
shared_memory->backing_block_offset = linheap_memory->size();
|
||||
|
@ -39,7 +44,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
|||
linheap_memory->insert(linheap_memory->end(), size, 0);
|
||||
memory_region->used += size;
|
||||
|
||||
shared_memory->linear_heap_phys_address = Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
|
||||
shared_memory->linear_heap_phys_address =
|
||||
Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
|
||||
|
||||
// Increase the amount of used linear heap memory for the owner process.
|
||||
if (shared_memory->owner_process != nullptr) {
|
||||
|
@ -51,18 +57,20 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
|||
Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
|
||||
}
|
||||
} else {
|
||||
// TODO(Subv): What happens if an application tries to create multiple memory blocks pointing to the same address?
|
||||
// TODO(Subv): What happens if an application tries to create multiple memory blocks
|
||||
// pointing to the same address?
|
||||
auto& vm_manager = shared_memory->owner_process->vm_manager;
|
||||
// The memory is already available and mapped in the owner process.
|
||||
auto vma = vm_manager.FindVMA(address)->second;
|
||||
// Copy it over to our own storage
|
||||
shared_memory->backing_block = std::make_shared<std::vector<u8>>(vma.backing_block->data() + vma.offset,
|
||||
vma.backing_block->data() + vma.offset + size);
|
||||
shared_memory->backing_block = std::make_shared<std::vector<u8>>(
|
||||
vma.backing_block->data() + vma.offset, vma.backing_block->data() + vma.offset + size);
|
||||
shared_memory->backing_block_offset = 0;
|
||||
// Unmap the existing pages
|
||||
vm_manager.UnmapRange(address, size);
|
||||
// Map our own block into the address space
|
||||
vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared);
|
||||
vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size,
|
||||
MemoryState::Shared);
|
||||
// Reprotect the block with the new permissions
|
||||
vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions));
|
||||
}
|
||||
|
@ -71,8 +79,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
|||
return shared_memory;
|
||||
}
|
||||
|
||||
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
|
||||
MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
|
||||
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
||||
u32 offset, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions,
|
||||
std::string name) {
|
||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
||||
|
||||
shared_memory->owner_process = nullptr;
|
||||
|
@ -88,27 +99,31 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vecto
|
|||
}
|
||||
|
||||
ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions) {
|
||||
MemoryPermission other_permissions) {
|
||||
|
||||
MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions;
|
||||
MemoryPermission own_other_permissions =
|
||||
target_process == owner_process ? this->permissions : this->other_permissions;
|
||||
|
||||
// Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
|
||||
if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
// Error out if the requested permissions don't match what the creator process allows.
|
||||
if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
|
||||
GetObjectId(), address, name.c_str());
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
// Heap-backed memory blocks can not be mapped with other_permissions = DontCare
|
||||
if (base_address != 0 && other_permissions == MemoryPermission::DontCare) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
|
||||
GetObjectId(), address, name.c_str());
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
// Error out if the provided permissions are not compatible with what the creator process needs.
|
||||
|
@ -116,12 +131,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
|||
static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
|
||||
GetObjectId(), address, name.c_str());
|
||||
return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
// TODO(Subv): Check for the Shared Device Mem flag in the creator process.
|
||||
/*if (was_created_with_shared_device_mem && address != 0) {
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}*/
|
||||
|
||||
// TODO(Subv): The same process that created a SharedMemory object
|
||||
|
@ -144,23 +161,29 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
|||
}
|
||||
|
||||
// Map the memory block into the target process
|
||||
auto result = target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
|
||||
auto result = target_process->vm_manager.MapMemoryBlock(
|
||||
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
|
||||
if (result.Failed()) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory",
|
||||
GetObjectId(), target_address, name.c_str());
|
||||
LOG_ERROR(
|
||||
Kernel,
|
||||
"cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory",
|
||||
GetObjectId(), target_address, name.c_str());
|
||||
return result.Code();
|
||||
}
|
||||
|
||||
return target_process->vm_manager.ReprotectRange(target_address, size, ConvertPermissions(permissions));
|
||||
return target_process->vm_manager.ReprotectRange(target_address, size,
|
||||
ConvertPermissions(permissions));
|
||||
}
|
||||
|
||||
ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
|
||||
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory.
|
||||
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not
|
||||
// mapped to a SharedMemory.
|
||||
return target_process->vm_manager.UnmapRange(address, size);
|
||||
}
|
||||
|
||||
VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
|
||||
u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
|
||||
u32 masked_permissions =
|
||||
static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
|
||||
return static_cast<VMAPermission>(masked_permissions);
|
||||
};
|
||||
|
||||
|
|
|
@ -16,15 +16,15 @@ namespace Kernel {
|
|||
|
||||
/// Permissions for mapped shared memory blocks
|
||||
enum class MemoryPermission : u32 {
|
||||
None = 0,
|
||||
Read = (1u << 0),
|
||||
Write = (1u << 1),
|
||||
ReadWrite = (Read | Write),
|
||||
Execute = (1u << 2),
|
||||
ReadExecute = (Read | Execute),
|
||||
WriteExecute = (Write | Execute),
|
||||
None = 0,
|
||||
Read = (1u << 0),
|
||||
Write = (1u << 1),
|
||||
ReadWrite = (Read | Write),
|
||||
Execute = (1u << 2),
|
||||
ReadExecute = (Read | Execute),
|
||||
WriteExecute = (Write | Execute),
|
||||
ReadWriteExecute = (Read | Write | Execute),
|
||||
DontCare = (1u << 28)
|
||||
DontCare = (1u << 28)
|
||||
};
|
||||
|
||||
class SharedMemory final : public Object {
|
||||
|
@ -34,13 +34,18 @@ public:
|
|||
* @param owner_process Process that created this shared memory object.
|
||||
* @param size Size of the memory block. Must be page-aligned.
|
||||
* @param permissions Permission restrictions applied to the process which created the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the
|
||||
* block.
|
||||
* @param address The address from which to map the Shared Memory.
|
||||
* @param region If the address is 0, the shared memory will be allocated in this region of the linear heap.
|
||||
* @param region If the address is 0, the shared memory will be allocated in this region of the
|
||||
* linear heap.
|
||||
* @param name Optional object name, used for debugging purposes.
|
||||
*/
|
||||
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address = 0, MemoryRegion region = MemoryRegion::BASE, std::string name = "Unknown");
|
||||
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address = 0,
|
||||
MemoryRegion region = MemoryRegion::BASE,
|
||||
std::string name = "Unknown");
|
||||
|
||||
/**
|
||||
* Creates a shared memory object from a block of memory managed by an HLE applet.
|
||||
|
@ -48,17 +53,27 @@ public:
|
|||
* @param offset The offset into the heap block that the SharedMemory will map.
|
||||
* @param size Size of the memory block. Must be page-aligned.
|
||||
* @param permissions Permission restrictions applied to the process which created the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the
|
||||
* block.
|
||||
* @param name Optional object name, used for debugging purposes.
|
||||
*/
|
||||
static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
|
||||
MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet");
|
||||
static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
||||
u32 offset, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions,
|
||||
std::string name = "Unknown Applet");
|
||||
|
||||
std::string GetTypeName() const override { return "SharedMemory"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "SharedMemory";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the specified MemoryPermission into the equivalent VMAPermission.
|
||||
|
@ -73,7 +88,8 @@ public:
|
|||
* @param permissions Memory block map permissions (specified by SVC field)
|
||||
* @param other_permissions Memory block map other permissions (specified by SVC field)
|
||||
*/
|
||||
ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
|
||||
ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions);
|
||||
|
||||
/**
|
||||
* Unmaps a shared memory block from the specified address in system memory
|
||||
|
@ -94,7 +110,8 @@ public:
|
|||
SharedPtr<Process> owner_process;
|
||||
/// Address of shared memory block in the owner process if specified.
|
||||
VAddr base_address;
|
||||
/// Physical address of the shared memory block in the linear heap if no address was specified during creation.
|
||||
/// Physical address of the shared memory block in the linear heap if no address was specified
|
||||
/// during creation.
|
||||
PAddr linear_heap_phys_address;
|
||||
/// Backing memory for this shared memory block.
|
||||
std::shared_ptr<std::vector<u8>> backing_block;
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
#include "core/core_timing.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
|
@ -46,7 +46,7 @@ static Kernel::HandleTable wakeup_callback_handle_table;
|
|||
static std::vector<SharedPtr<Thread>> thread_list;
|
||||
|
||||
// Lists only ready thread ids.
|
||||
static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue;
|
||||
static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
|
||||
|
||||
static Thread* current_thread;
|
||||
|
||||
|
@ -61,8 +61,10 @@ inline static u32 const NewThreadId() {
|
|||
return next_thread_id++;
|
||||
}
|
||||
|
||||
Thread::Thread() {}
|
||||
Thread::~Thread() {}
|
||||
Thread::Thread() {
|
||||
}
|
||||
Thread::~Thread() {
|
||||
}
|
||||
|
||||
Thread* GetCurrentThread() {
|
||||
return current_thread;
|
||||
|
@ -103,7 +105,7 @@ void Thread::Stop() {
|
|||
|
||||
// Clean up thread from ready queue
|
||||
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
|
||||
if (status == THREADSTATUS_READY){
|
||||
if (status == THREADSTATUS_READY) {
|
||||
ready_queue.remove(current_priority, this);
|
||||
}
|
||||
|
||||
|
@ -119,7 +121,8 @@ void Thread::Stop() {
|
|||
|
||||
// Mark the TLS slot in the thread's page as free.
|
||||
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
||||
u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
u32 tls_slot =
|
||||
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
|
||||
|
||||
HLE::Reschedule(__func__);
|
||||
|
@ -137,7 +140,7 @@ Thread* ArbitrateHighestPriorityThread(u32 address) {
|
|||
if (thread == nullptr)
|
||||
continue;
|
||||
|
||||
if(thread->current_priority <= priority) {
|
||||
if (thread->current_priority <= priority) {
|
||||
highest_priority_thread = thread.get();
|
||||
priority = thread->current_priority;
|
||||
}
|
||||
|
@ -170,7 +173,7 @@ static void PriorityBoostStarvedThreads() {
|
|||
// on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler
|
||||
// should probably be reversed to verify this.
|
||||
|
||||
const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long
|
||||
const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long
|
||||
|
||||
u64 delta = current_ticks - thread->last_running_ticks;
|
||||
|
||||
|
@ -193,10 +196,12 @@ static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* threa
|
|||
|
||||
if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) {
|
||||
// svc #0x24 (WaitSynchronization1)
|
||||
return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]);
|
||||
return std::make_tuple(&thread->context.cpu_registers[2],
|
||||
&thread->context.cpu_registers[3]);
|
||||
} else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) {
|
||||
// svc #0x25 (WaitSynchronizationN)
|
||||
return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]);
|
||||
return std::make_tuple(&thread->context.cpu_registers[0],
|
||||
&thread->context.cpu_registers[4]);
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
|
@ -245,7 +250,8 @@ static void SwitchContext(Thread* new_thread) {
|
|||
|
||||
// Load context of new thread
|
||||
if (new_thread) {
|
||||
DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
|
||||
DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY,
|
||||
"Thread must be ready to become running.");
|
||||
|
||||
// Cancel any outstanding wakeup events for this thread
|
||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
|
||||
|
@ -263,7 +269,7 @@ static void SwitchContext(Thread* new_thread) {
|
|||
new_thread->context.pc -= thumb_mode ? 2 : 4;
|
||||
|
||||
// Get the register for timeout parameter
|
||||
u32* timeout_low, *timeout_high;
|
||||
u32 *timeout_low, *timeout_high;
|
||||
std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread);
|
||||
|
||||
// Update the timeout parameter
|
||||
|
@ -307,7 +313,7 @@ static Thread* PopNextReadyThread() {
|
|||
// Otherwise just keep going with the current thread
|
||||
next = thread;
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
next = ready_queue.pop_first();
|
||||
}
|
||||
|
||||
|
@ -321,7 +327,8 @@ void WaitCurrentThread_Sleep() {
|
|||
HLE::Reschedule(__func__);
|
||||
}
|
||||
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all) {
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
|
||||
bool wait_set_output, bool wait_all) {
|
||||
Thread* thread = GetCurrentThread();
|
||||
thread->wait_set_output = wait_set_output;
|
||||
thread->wait_all = wait_all;
|
||||
|
@ -352,7 +359,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
|||
|
||||
if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
|
||||
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
|
||||
ErrorSummary::StatusChanged, ErrorLevel::Info));
|
||||
ErrorSummary::StatusChanged,
|
||||
ErrorLevel::Info));
|
||||
|
||||
if (thread->wait_set_output)
|
||||
thread->SetWaitSynchronizationOutput(-1);
|
||||
|
@ -372,25 +380,25 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
|||
|
||||
void Thread::ResumeFromWait() {
|
||||
switch (status) {
|
||||
case THREADSTATUS_WAIT_SYNCH:
|
||||
case THREADSTATUS_WAIT_ARB:
|
||||
case THREADSTATUS_WAIT_SLEEP:
|
||||
break;
|
||||
case THREADSTATUS_WAIT_SYNCH:
|
||||
case THREADSTATUS_WAIT_ARB:
|
||||
case THREADSTATUS_WAIT_SLEEP:
|
||||
break;
|
||||
|
||||
case THREADSTATUS_READY:
|
||||
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
||||
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
||||
// already been set to THREADSTATUS_READY.
|
||||
return;
|
||||
case THREADSTATUS_READY:
|
||||
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
||||
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
||||
// already been set to THREADSTATUS_READY.
|
||||
return;
|
||||
|
||||
case THREADSTATUS_RUNNING:
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
|
||||
return;
|
||||
case THREADSTATUS_DEAD:
|
||||
// This should never happen, as threads must complete before being stopped.
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.",
|
||||
GetObjectId());
|
||||
return;
|
||||
case THREADSTATUS_RUNNING:
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
|
||||
return;
|
||||
case THREADSTATUS_DEAD:
|
||||
// This should never happen, as threads must complete before being stopped.
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.",
|
||||
GetObjectId());
|
||||
return;
|
||||
}
|
||||
|
||||
ready_queue.push_back(current_priority, this);
|
||||
|
@ -405,7 +413,8 @@ static void DebugThreadQueue() {
|
|||
if (!thread) {
|
||||
LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD");
|
||||
} else {
|
||||
LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId());
|
||||
LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority,
|
||||
GetCurrentThread()->GetObjectId());
|
||||
}
|
||||
|
||||
for (auto& t : thread_list) {
|
||||
|
@ -448,7 +457,8 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
|
|||
* @param entry_point Address of entry point for execution
|
||||
* @param arg User argument for thread
|
||||
*/
|
||||
static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) {
|
||||
static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point,
|
||||
u32 arg) {
|
||||
memset(&context, 0, sizeof(Core::ThreadContext));
|
||||
|
||||
context.cpu_registers[0] = arg;
|
||||
|
@ -458,11 +468,11 @@ static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32
|
|||
}
|
||||
|
||||
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority,
|
||||
u32 arg, s32 processor_id, VAddr stack_top) {
|
||||
u32 arg, s32 processor_id, VAddr stack_top) {
|
||||
if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
|
||||
s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
|
||||
LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
|
||||
name.c_str(), priority, new_priority);
|
||||
LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", name.c_str(),
|
||||
priority, new_priority);
|
||||
// TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
|
||||
// validity of this
|
||||
priority = new_priority;
|
||||
|
@ -472,7 +482,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
|||
LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
|
||||
// TODO: Verify error
|
||||
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
SharedPtr<Thread> thread(new Thread);
|
||||
|
@ -511,8 +521,10 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
|||
auto& linheap_memory = memory_region->linear_heap_memory;
|
||||
|
||||
if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
|
||||
LOG_ERROR(Kernel_SVC, "Not enough space in region to allocate a new TLS page for thread");
|
||||
return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Permanent);
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Not enough space in region to allocate a new TLS page for thread");
|
||||
return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
|
||||
ErrorSummary::OutOfResource, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
u32 offset = linheap_memory->size();
|
||||
|
@ -537,7 +549,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
|||
|
||||
// Mark the slot as used
|
||||
tls_slots[available_page].set(available_slot);
|
||||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
|
||||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
||||
available_slot * Memory::TLS_ENTRY_SIZE;
|
||||
|
||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||
// to initialize the context
|
||||
|
@ -551,10 +564,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
|||
return MakeResult<SharedPtr<Thread>>(std::move(thread));
|
||||
}
|
||||
|
||||
// TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be returned.
|
||||
// TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be
|
||||
// returned.
|
||||
static void ClampPriority(const Thread* thread, s32* priority) {
|
||||
if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) {
|
||||
DEBUG_ASSERT_MSG(false, "Application passed an out of range priority. An error should be returned.");
|
||||
DEBUG_ASSERT_MSG(
|
||||
false, "Application passed an out of range priority. An error should be returned.");
|
||||
|
||||
s32 new_priority = MathUtil::Clamp<s32>(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
|
||||
LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
|
||||
|
@ -586,12 +601,13 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
|
|||
DEBUG_ASSERT(!GetCurrentThread());
|
||||
|
||||
// Initialize new "main" thread
|
||||
auto thread_res = Thread::Create("main", entry_point, priority, 0,
|
||||
THREADPROCESSORID_0, Memory::HEAP_VADDR_END);
|
||||
auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
|
||||
Memory::HEAP_VADDR_END);
|
||||
|
||||
SharedPtr<Thread> thread = thread_res.MoveFrom();
|
||||
|
||||
thread->context.fpscr = FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
|
||||
thread->context.fpscr =
|
||||
FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
|
||||
|
||||
// Run new "main" thread
|
||||
SwitchContext(thread.get());
|
||||
|
|
|
@ -17,29 +17,29 @@
|
|||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
enum ThreadPriority : s32{
|
||||
THREADPRIO_HIGHEST = 0, ///< Highest thread priority
|
||||
THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
|
||||
THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps
|
||||
THREADPRIO_LOWEST = 63, ///< Lowest thread priority
|
||||
enum ThreadPriority : s32 {
|
||||
THREADPRIO_HIGHEST = 0, ///< Highest thread priority
|
||||
THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
|
||||
THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps
|
||||
THREADPRIO_LOWEST = 63, ///< Lowest thread priority
|
||||
};
|
||||
|
||||
enum ThreadProcessorId : s32 {
|
||||
THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader
|
||||
THREADPROCESSORID_ALL = -1, ///< Run thread on either core
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore)
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore)
|
||||
THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this
|
||||
THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader
|
||||
THREADPROCESSORID_ALL = -1, ///< Run thread on either core
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore)
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore)
|
||||
THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this
|
||||
};
|
||||
|
||||
enum ThreadStatus {
|
||||
THREADSTATUS_RUNNING, ///< Currently running
|
||||
THREADSTATUS_READY, ///< Ready to run
|
||||
THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
|
||||
THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
|
||||
THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC
|
||||
THREADSTATUS_DORMANT, ///< Created but not yet made ready
|
||||
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
|
||||
THREADSTATUS_RUNNING, ///< Currently running
|
||||
THREADSTATUS_READY, ///< Ready to run
|
||||
THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
|
||||
THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
|
||||
THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC
|
||||
THREADSTATUS_DORMANT, ///< Created but not yet made ready
|
||||
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
|
||||
};
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -60,13 +60,19 @@ public:
|
|||
* @return A shared pointer to the newly created thread
|
||||
*/
|
||||
static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,
|
||||
u32 arg, s32 processor_id, VAddr stack_top);
|
||||
u32 arg, s32 processor_id, VAddr stack_top);
|
||||
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override { return "Thread"; }
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
std::string GetTypeName() const override {
|
||||
return "Thread";
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Thread;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
@ -75,7 +81,9 @@ public:
|
|||
* Gets the thread's current priority
|
||||
* @return The current thread's priority
|
||||
*/
|
||||
s32 GetPriority() const { return current_priority; }
|
||||
s32 GetPriority() const {
|
||||
return current_priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the thread's current priority
|
||||
|
@ -93,7 +101,9 @@ public:
|
|||
* Gets the thread's thread ID
|
||||
* @return The thread's ID
|
||||
*/
|
||||
u32 GetThreadId() const { return thread_id; }
|
||||
u32 GetThreadId() const {
|
||||
return thread_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes a thread from waiting
|
||||
|
@ -127,7 +137,9 @@ public:
|
|||
* Returns the Thread Local Storage address of the current thread
|
||||
* @returns VAddr of the thread's TLS
|
||||
*/
|
||||
VAddr GetTLSAddress() const { return tls_address; }
|
||||
VAddr GetTLSAddress() const {
|
||||
return tls_address;
|
||||
}
|
||||
|
||||
Core::ThreadContext context;
|
||||
|
||||
|
@ -137,8 +149,8 @@ public:
|
|||
u32 entry_point;
|
||||
u32 stack_top;
|
||||
|
||||
s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
|
||||
s32 current_priority; ///< Current thread priority, can be temporarily changed
|
||||
s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
|
||||
s32 current_priority; ///< Current thread priority, can be temporarily changed
|
||||
|
||||
u64 last_running_ticks; ///< CPU tick when thread was last running
|
||||
|
||||
|
@ -151,11 +163,11 @@ public:
|
|||
/// Mutexes currently held by this thread, which will be released when it exits.
|
||||
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
|
||||
|
||||
SharedPtr<Process> owner_process; ///< Process that owns this thread
|
||||
SharedPtr<Process> owner_process; ///< Process that owns this thread
|
||||
std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
|
||||
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
|
||||
bool wait_all; ///< True if the thread is waiting on all objects before resuming
|
||||
bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
|
||||
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
|
||||
bool wait_all; ///< True if the thread is waiting on all objects before resuming
|
||||
bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
|
||||
|
||||
std::string name;
|
||||
|
||||
|
@ -205,10 +217,12 @@ void WaitCurrentThread_Sleep();
|
|||
/**
|
||||
* Waits the current thread from a WaitSynchronization call
|
||||
* @param wait_objects Kernel objects that we are waiting on
|
||||
* @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only)
|
||||
* @param wait_set_output If true, set the output parameter on thread wakeup (for
|
||||
* WaitSynchronizationN only)
|
||||
* @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
|
||||
*/
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all);
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
|
||||
bool wait_set_output, bool wait_all);
|
||||
|
||||
/**
|
||||
* Waits the current thread from an ArbitrateAddress call
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -20,8 +20,10 @@ static int timer_callback_event_type;
|
|||
// us to simply use a pool index or similar.
|
||||
static Kernel::HandleTable timer_callback_handle_table;
|
||||
|
||||
Timer::Timer() {}
|
||||
Timer::~Timer() {}
|
||||
Timer::Timer() {
|
||||
}
|
||||
Timer::~Timer() {
|
||||
}
|
||||
|
||||
SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
|
||||
SharedPtr<Timer> timer(new Timer);
|
||||
|
@ -41,7 +43,7 @@ bool Timer::ShouldWait() {
|
|||
}
|
||||
|
||||
void Timer::Acquire() {
|
||||
ASSERT_MSG( !ShouldWait(), "object unavailable!");
|
||||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
||||
|
||||
if (reset_type == ResetType::OneShot)
|
||||
signaled = false;
|
||||
|
@ -55,8 +57,8 @@ void Timer::Set(s64 initial, s64 interval) {
|
|||
interval_delay = interval;
|
||||
|
||||
u64 initial_microseconds = initial / 1000;
|
||||
CoreTiming::ScheduleEvent(usToCycles(initial_microseconds),
|
||||
timer_callback_event_type, callback_handle);
|
||||
CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
|
||||
callback_handle);
|
||||
|
||||
HLE::Reschedule(__func__);
|
||||
}
|
||||
|
@ -73,7 +75,8 @@ void Timer::Clear() {
|
|||
|
||||
/// The timer callback event, called when a timer is fired
|
||||
static void TimerCallback(u64 timer_handle, int cycles_late) {
|
||||
SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
|
||||
SharedPtr<Timer> timer =
|
||||
timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
|
||||
|
||||
if (timer == nullptr) {
|
||||
LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle);
|
||||
|
@ -91,7 +94,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
|
|||
// Reschedule the timer with the interval delay
|
||||
u64 interval_microseconds = timer->interval_delay / 1000;
|
||||
CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
|
||||
timer_callback_event_type, timer_handle);
|
||||
timer_callback_event_type, timer_handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,19 +21,25 @@ public:
|
|||
*/
|
||||
static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Timer"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Timer";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Timer;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
ResetType reset_type; ///< The ResetType of this timer
|
||||
ResetType reset_type; ///< The ResetType of this timer
|
||||
|
||||
bool signaled; ///< Whether the timer has been signaled or not
|
||||
std::string name; ///< Name of timer (optional)
|
||||
bool signaled; ///< Whether the timer has been signaled or not
|
||||
std::string name; ///< Name of timer (optional)
|
||||
|
||||
u64 initial_delay; ///< The delay until the timer fires for the first time
|
||||
u64 interval_delay; ///< The delay until the timer fires after the first time
|
||||
u64 initial_delay; ///< The delay until the timer fires for the first time
|
||||
u64 interval_delay; ///< The delay until the timer fires after the first time
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace Kernel {
|
|||
|
||||
static const char* GetMemoryStateName(MemoryState state) {
|
||||
static const char* names[] = {
|
||||
"Free", "Reserved", "IO", "Static", "Code", "Private", "Shared", "Continuous", "Aliased",
|
||||
"Alias", "AliasCode", "Locked",
|
||||
"Free", "Reserved", "IO", "Static", "Code", "Private",
|
||||
"Shared", "Continuous", "Aliased", "Alias", "AliasCode", "Locked",
|
||||
};
|
||||
|
||||
return names[(int)state];
|
||||
|
@ -24,13 +24,12 @@ static const char* GetMemoryStateName(MemoryState state) {
|
|||
|
||||
bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
|
||||
ASSERT(base + size == next.base);
|
||||
if (permissions != next.permissions ||
|
||||
meminfo_state != next.meminfo_state ||
|
||||
type != next.type) {
|
||||
if (permissions != next.permissions || meminfo_state != next.meminfo_state ||
|
||||
type != next.type) {
|
||||
return false;
|
||||
}
|
||||
if (type == VMAType::AllocatedMemoryBlock &&
|
||||
(backing_block != next.backing_block || offset + size != next.offset)) {
|
||||
(backing_block != next.backing_block || offset + size != next.offset)) {
|
||||
return false;
|
||||
}
|
||||
if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
|
||||
|
@ -70,7 +69,9 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
|
|||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
|
||||
std::shared_ptr<std::vector<u8>> block, size_t offset, u32 size, MemoryState state) {
|
||||
std::shared_ptr<std::vector<u8>> block,
|
||||
size_t offset, u32 size,
|
||||
MemoryState state) {
|
||||
ASSERT(block != nullptr);
|
||||
ASSERT(offset + size <= block->size());
|
||||
|
||||
|
@ -89,7 +90,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
|
|||
return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) {
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size,
|
||||
MemoryState state) {
|
||||
ASSERT(memory != nullptr);
|
||||
|
||||
// This is the appropriately sized VMA that will turn into our allocation.
|
||||
|
@ -106,7 +108,9 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * m
|
|||
return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler) {
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size,
|
||||
MemoryState state,
|
||||
Memory::MMIORegionPointer mmio_handler) {
|
||||
// This is the appropriately sized VMA that will turn into our allocation.
|
||||
CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
|
||||
VirtualMemoryArea& final_vma = vma_handle->second;
|
||||
|
@ -191,15 +195,16 @@ void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
|
|||
void VMManager::LogLayout(Log::Level log_level) const {
|
||||
for (const auto& p : vma_map) {
|
||||
const VirtualMemoryArea& vma = p.second;
|
||||
LOG_GENERIC(Log::Class::Kernel, log_level, "%08X - %08X size: %8X %c%c%c %s",
|
||||
vma.base, vma.base + vma.size, vma.size,
|
||||
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', GetMemoryStateName(vma.meminfo_state));
|
||||
LOG_GENERIC(Log::Class::Kernel, log_level, "%08X - %08X size: %8X %c%c%c %s", vma.base,
|
||||
vma.base + vma.size, vma.size,
|
||||
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-',
|
||||
GetMemoryStateName(vma.meminfo_state));
|
||||
}
|
||||
}
|
||||
|
||||
VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
|
||||
VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) {
|
||||
// This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
|
||||
// non-const access to its container.
|
||||
return vma_map.erase(iter, iter); // Erases an empty range of elements
|
||||
|
@ -337,5 +342,4 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
const ResultCode ERR_INVALID_ADDRESS{ // 0xE0E01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
|
||||
const ResultCode ERR_INVALID_ADDRESS{// 0xE0E01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
|
||||
|
||||
const ResultCode ERR_INVALID_ADDRESS_STATE{ // 0xE0A01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Usage};
|
||||
const ResultCode ERR_INVALID_ADDRESS_STATE{// 0xE0A01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Usage};
|
||||
|
||||
enum class VMAType : u8 {
|
||||
/// VMA represents an unmapped region of the address space.
|
||||
|
@ -115,7 +115,8 @@ class VMManager final {
|
|||
// TODO(yuriks): Make page tables switchable to support multiple VMManagers
|
||||
public:
|
||||
/**
|
||||
* The maximum amount of address space managed by the kernel. Addresses above this are never used.
|
||||
* The maximum amount of address space managed by the kernel. Addresses above this are never
|
||||
* used.
|
||||
* @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000.
|
||||
*/
|
||||
static const u32 MAX_ADDRESS = 0x40000000;
|
||||
|
@ -151,7 +152,7 @@ public:
|
|||
* @param state MemoryState tag to attach to the VMA.
|
||||
*/
|
||||
ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
|
||||
size_t offset, u32 size, MemoryState state);
|
||||
size_t offset, u32 size, MemoryState state);
|
||||
|
||||
/**
|
||||
* Maps an unmanaged host memory pointer at a given address.
|
||||
|
@ -172,7 +173,8 @@ public:
|
|||
* @param state MemoryState tag to attach to the VMA.
|
||||
* @param mmio_handler The handler that will implement read and write for this MMIO region.
|
||||
*/
|
||||
ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler);
|
||||
ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state,
|
||||
Memory::MMIORegionPointer mmio_handler);
|
||||
|
||||
/// Unmaps a range of addresses, splitting VMAs as necessary.
|
||||
ResultCode UnmapRange(VAddr target, u32 size);
|
||||
|
@ -228,5 +230,4 @@ private:
|
|||
/// Updates the pages corresponding to this VMA so they match the VMA's attributes.
|
||||
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ enum class ErrorDescription : u32 {
|
|||
FS_InvalidOpenFlags = 230,
|
||||
FS_NotAFile = 250,
|
||||
FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
|
||||
OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage
|
||||
OutofRangeOrMisalignedAddress =
|
||||
513, // TODO(purpasmart): Check if this name fits its actual usage
|
||||
GPU_FirstInitialization = 519,
|
||||
FS_InvalidPath = 702,
|
||||
InvalidSection = 1000,
|
||||
|
@ -168,15 +169,15 @@ enum class ErrorSummary : u32 {
|
|||
Success = 0,
|
||||
NothingHappened = 1,
|
||||
WouldBlock = 2,
|
||||
OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to
|
||||
///< execute the operation.
|
||||
NotFound = 4, ///< A file or resource was not found.
|
||||
OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to
|
||||
///< execute the operation.
|
||||
NotFound = 4, ///< A file or resource was not found.
|
||||
InvalidState = 5,
|
||||
NotSupported = 6, ///< The operation is not supported or not implemented.
|
||||
InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime
|
||||
///< context. (Invalid handle, out-of-bounds pointer or size, etc.)
|
||||
WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use
|
||||
///< with the function. (E.g. Invalid enum value)
|
||||
NotSupported = 6, ///< The operation is not supported or not implemented.
|
||||
InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime
|
||||
///< context. (Invalid handle, out-of-bounds pointer or size, etc.)
|
||||
WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use
|
||||
///< with the function. (E.g. Invalid enum value)
|
||||
Canceled = 9,
|
||||
StatusChanged = 10,
|
||||
Internal = 11,
|
||||
|
@ -208,19 +209,25 @@ union ResultCode {
|
|||
BitField<21, 6, ErrorSummary> summary;
|
||||
BitField<27, 5, ErrorLevel> level;
|
||||
|
||||
// The last bit of `level` is checked by apps and the kernel to determine if a result code is an error
|
||||
// The last bit of `level` is checked by apps and the kernel to determine if a result code is an
|
||||
// error
|
||||
BitField<31, 1, u32> is_error;
|
||||
|
||||
explicit ResultCode(u32 raw) : raw(raw) {}
|
||||
ResultCode(ErrorDescription description_, ErrorModule module_,
|
||||
ErrorSummary summary_, ErrorLevel level_) : raw(0) {
|
||||
explicit ResultCode(u32 raw) : raw(raw) {
|
||||
}
|
||||
ResultCode(ErrorDescription description_, ErrorModule module_, ErrorSummary summary_,
|
||||
ErrorLevel level_)
|
||||
: raw(0) {
|
||||
description.Assign(description_);
|
||||
module.Assign(module_);
|
||||
summary.Assign(summary_);
|
||||
level.Assign(level_);
|
||||
}
|
||||
|
||||
ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; }
|
||||
ResultCode& operator=(const ResultCode& o) {
|
||||
raw = o.raw;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IsSuccess() const {
|
||||
return is_error == 0;
|
||||
|
@ -246,8 +253,8 @@ const ResultCode RESULT_SUCCESS(0);
|
|||
|
||||
/// Might be returned instead of a dummy success for unimplemented APIs.
|
||||
inline ResultCode UnimplementedFunction(ErrorModule module) {
|
||||
return ResultCode(ErrorDescription::NotImplemented, module,
|
||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotImplemented, module, ErrorSummary::NotSupported,
|
||||
ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -285,10 +292,9 @@ inline ResultCode UnimplementedFunction(ErrorModule module) {
|
|||
template <typename T>
|
||||
class ResultVal {
|
||||
public:
|
||||
/// Constructs an empty `ResultVal` with the given error code. The code must not be a success code.
|
||||
ResultVal(ResultCode error_code = ResultCode(-1))
|
||||
: result_code(error_code)
|
||||
{
|
||||
/// Constructs an empty `ResultVal` with the given error code. The code must not be a success
|
||||
/// code.
|
||||
ResultVal(ResultCode error_code = ResultCode(-1)) : result_code(error_code) {
|
||||
ASSERT(error_code.IsError());
|
||||
}
|
||||
|
||||
|
@ -303,17 +309,13 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
ResultVal(const ResultVal& o)
|
||||
: result_code(o.result_code)
|
||||
{
|
||||
ResultVal(const ResultVal& o) : result_code(o.result_code) {
|
||||
if (!o.empty()) {
|
||||
new (&object) T(o.object);
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal(ResultVal&& o)
|
||||
: result_code(o.result_code)
|
||||
{
|
||||
ResultVal(ResultVal&& o) : result_code(o.result_code) {
|
||||
if (!o.empty()) {
|
||||
new (&object) T(std::move(o.object));
|
||||
}
|
||||
|
@ -357,19 +359,35 @@ public:
|
|||
}
|
||||
|
||||
/// Returns true if the `ResultVal` contains an error code and no value.
|
||||
bool empty() const { return result_code.IsError(); }
|
||||
bool empty() const {
|
||||
return result_code.IsError();
|
||||
}
|
||||
|
||||
/// Returns true if the `ResultVal` contains a return value.
|
||||
bool Succeeded() const { return result_code.IsSuccess(); }
|
||||
bool Succeeded() const {
|
||||
return result_code.IsSuccess();
|
||||
}
|
||||
/// Returns true if the `ResultVal` contains an error code and no value.
|
||||
bool Failed() const { return empty(); }
|
||||
bool Failed() const {
|
||||
return empty();
|
||||
}
|
||||
|
||||
ResultCode Code() const { return result_code; }
|
||||
ResultCode Code() const {
|
||||
return result_code;
|
||||
}
|
||||
|
||||
const T& operator* () const { return object; }
|
||||
T& operator* () { return object; }
|
||||
const T* operator->() const { return &object; }
|
||||
T* operator->() { return &object; }
|
||||
const T& operator*() const {
|
||||
return object;
|
||||
}
|
||||
T& operator*() {
|
||||
return object;
|
||||
}
|
||||
const T* operator->() const {
|
||||
return &object;
|
||||
}
|
||||
T* operator->() {
|
||||
return &object;
|
||||
}
|
||||
|
||||
/// Returns the value contained in this `ResultVal`, or the supplied default if it is missing.
|
||||
template <typename U>
|
||||
|
@ -390,7 +408,9 @@ public:
|
|||
private:
|
||||
// A union is used to allocate the storage for the value, while allowing us to construct and
|
||||
// destruct it at will.
|
||||
union { T object; };
|
||||
union {
|
||||
T object;
|
||||
};
|
||||
ResultCode result_code;
|
||||
};
|
||||
|
||||
|
@ -409,8 +429,8 @@ ResultVal<T> MakeResult(Args&&... args) {
|
|||
* variable declaration. If it fails the return code is returned from the current function. Thus it
|
||||
* can be used to cascade errors out, achieving something akin to exception handling.
|
||||
*/
|
||||
#define CASCADE_RESULT(target, source) \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).Failed()) \
|
||||
return CONCAT2(check_result_L, __LINE__).Code(); \
|
||||
target = std::move(*CONCAT2(check_result_L, __LINE__))
|
||||
#define CASCADE_RESULT(target, source) \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).Failed()) \
|
||||
return CONCAT2(check_result_L, __LINE__).Code(); \
|
||||
target = std::move(*CONCAT2(check_result_L, __LINE__))
|
||||
|
|
|
@ -47,7 +47,7 @@ static void GetWifiStatus(Service::Interface* self) {
|
|||
// it returns a valid result without implementing full functionality.
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 0; // Connection type set to none
|
||||
cmd_buff[2] = 0; // Connection type set to none
|
||||
|
||||
LOG_WARNING(Service_AC, "(STUBBED) called");
|
||||
}
|
||||
|
@ -62,29 +62,29 @@ static void IsConnected(Service::Interface* self) {
|
|||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = false; // Not connected to ac:u service
|
||||
cmd_buff[2] = false; // Not connected to ac:u service
|
||||
|
||||
LOG_WARNING(Service_AC, "(STUBBED) called");
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010000, nullptr, "CreateDefaultConfig"},
|
||||
{0x00040006, nullptr, "ConnectAsync"},
|
||||
{0x00050002, nullptr, "GetConnectResult"},
|
||||
{0x00080004, CloseAsync, "CloseAsync"},
|
||||
{0x00090002, nullptr, "GetCloseResult"},
|
||||
{0x000A0000, nullptr, "GetLastErrorCode"},
|
||||
{0x000D0000, GetWifiStatus, "GetWifiStatus"},
|
||||
{0x000E0042, nullptr, "GetCurrentAPInfo"},
|
||||
{0x00100042, nullptr, "GetCurrentNZoneInfo"},
|
||||
{0x00110042, nullptr, "GetNZoneApNumService"},
|
||||
{0x00240042, nullptr, "AddDenyApType"},
|
||||
{0x00270002, nullptr, "GetInfraPriority"},
|
||||
{0x002D0082, nullptr, "SetRequestEulaVersion"},
|
||||
{0x00300004, nullptr, "RegisterDisconnectEvent"},
|
||||
{0x003C0042, nullptr, "GetAPSSIDList"},
|
||||
{0x003E0042, IsConnected, "IsConnected"},
|
||||
{0x00400042, nullptr, "SetClientVersion"},
|
||||
{0x00010000, nullptr, "CreateDefaultConfig"},
|
||||
{0x00040006, nullptr, "ConnectAsync"},
|
||||
{0x00050002, nullptr, "GetConnectResult"},
|
||||
{0x00080004, CloseAsync, "CloseAsync"},
|
||||
{0x00090002, nullptr, "GetCloseResult"},
|
||||
{0x000A0000, nullptr, "GetLastErrorCode"},
|
||||
{0x000D0000, GetWifiStatus, "GetWifiStatus"},
|
||||
{0x000E0042, nullptr, "GetCurrentAPInfo"},
|
||||
{0x00100042, nullptr, "GetCurrentNZoneInfo"},
|
||||
{0x00110042, nullptr, "GetNZoneApNumService"},
|
||||
{0x00240042, nullptr, "AddDenyApType"},
|
||||
{0x00270002, nullptr, "GetInfraPriority"},
|
||||
{0x002D0082, nullptr, "SetRequestEulaVersion"},
|
||||
{0x00300004, nullptr, "RegisterDisconnectEvent"},
|
||||
{0x003C0042, nullptr, "GetAPSSIDList"},
|
||||
{0x003E0042, IsConnected, "IsConnected"},
|
||||
{0x00400042, nullptr, "SetClientVersion"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -6,19 +6,19 @@
|
|||
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/am_app.h"
|
||||
#include "core/hle/service/am/am_net.h"
|
||||
#include "core/hle/service/am/am_sys.h"
|
||||
#include "core/hle/service/am/am_u.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace AM {
|
||||
|
||||
static std::array<u32, 3> am_content_count = { 0, 0, 0 };
|
||||
static std::array<u32, 3> am_titles_count = { 0, 0, 0 };
|
||||
static std::array<u32, 3> am_titles_list_count = { 0, 0, 0 };
|
||||
static std::array<u32, 3> am_content_count = {0, 0, 0};
|
||||
static std::array<u32, 3> am_titles_count = {0, 0, 0};
|
||||
static std::array<u32, 3> am_titles_list_count = {0, 0, 0};
|
||||
static u32 am_ticket_count = 0;
|
||||
static u32 am_ticket_list_count = 0;
|
||||
|
||||
|
@ -29,7 +29,8 @@ void GetTitleCount(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_titles_count[media_type];
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_count=0x%08x", media_type, am_titles_count[media_type]);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_count=0x%08x", media_type,
|
||||
am_titles_count[media_type]);
|
||||
}
|
||||
|
||||
void FindContentInfos(Service::Interface* self) {
|
||||
|
@ -43,8 +44,10 @@ void FindContentInfos(Service::Interface* self) {
|
|||
am_content_count[media_type] = cmd_buff[4];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016llx, content_cound=%u, content_ids_pointer=0x%08x, content_info_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer, content_info_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016llx, content_cound=%u, "
|
||||
"content_ids_pointer=0x%08x, content_info_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer,
|
||||
content_info_pointer);
|
||||
}
|
||||
|
||||
void ListContentInfos(Service::Interface* self) {
|
||||
|
@ -59,8 +62,10 @@ void ListContentInfos(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_content_count[media_type];
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, content_count=%u, title_id=0x%016" PRIx64 ", start_index=0x%08x, content_info_pointer=0x%08X",
|
||||
media_type, am_content_count[media_type], title_id, start_index, content_info_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, content_count=%u, title_id=0x%016" PRIx64
|
||||
", start_index=0x%08x, content_info_pointer=0x%08X",
|
||||
media_type, am_content_count[media_type], title_id, start_index,
|
||||
content_info_pointer);
|
||||
}
|
||||
|
||||
void DeleteContents(Service::Interface* self) {
|
||||
|
@ -73,8 +78,9 @@ void DeleteContents(Service::Interface* self) {
|
|||
am_content_count[media_type] = cmd_buff[4];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016" PRIx64 ", content_count=%u, content_ids_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016" PRIx64
|
||||
", content_count=%u, content_ids_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer);
|
||||
}
|
||||
|
||||
void GetTitleList(Service::Interface* self) {
|
||||
|
@ -87,8 +93,10 @@ void GetTitleList(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_titles_list_count[media_type];
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, titles_list_count=0x%08X, title_ids_output_pointer=0x%08X",
|
||||
media_type, am_titles_list_count[media_type], title_ids_output_pointer);
|
||||
LOG_WARNING(
|
||||
Service_AM,
|
||||
"(STUBBED) media_type=%u, titles_list_count=0x%08X, title_ids_output_pointer=0x%08X",
|
||||
media_type, am_titles_list_count[media_type], title_ids_output_pointer);
|
||||
}
|
||||
|
||||
void GetTitleInfo(Service::Interface* self) {
|
||||
|
@ -101,7 +109,8 @@ void GetTitleInfo(Service::Interface* self) {
|
|||
am_titles_count[media_type] = cmd_buff[2];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, total_titles=0x%08X, title_id_list_pointer=0x%08X, title_list_pointer=0x%08X",
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, total_titles=0x%08X, "
|
||||
"title_id_list_pointer=0x%08X, title_list_pointer=0x%08X",
|
||||
media_type, am_titles_count[media_type], title_id_list_pointer, title_list_pointer);
|
||||
}
|
||||
|
||||
|
@ -122,8 +131,9 @@ void ListDataTitleTicketInfos(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_ticket_count;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) ticket_count=0x%08X, title_id=0x%016" PRIx64 ", start_index=0x%08X, ticket_info_pointer=0x%08X",
|
||||
am_ticket_count, title_id, start_index, ticket_info_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) ticket_count=0x%08X, title_id=0x%016" PRIx64
|
||||
", start_index=0x%08X, ticket_info_pointer=0x%08X",
|
||||
am_ticket_count, title_id, start_index, ticket_info_pointer);
|
||||
}
|
||||
|
||||
void GetNumContentInfos(Service::Interface* self) {
|
||||
|
@ -140,7 +150,7 @@ void DeleteTicket(Service::Interface* self) {
|
|||
u64 title_id = (static_cast<u64>(cmd_buff[2]) << 32) | cmd_buff[1];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "",title_id);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id);
|
||||
}
|
||||
|
||||
void GetTicketCount(Service::Interface* self) {
|
||||
|
@ -148,7 +158,7 @@ void GetTicketCount(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_ticket_count;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called ticket_count=0x%08x",am_ticket_count);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called ticket_count=0x%08x", am_ticket_count);
|
||||
}
|
||||
|
||||
void GetTicketList(Service::Interface* self) {
|
||||
|
@ -161,8 +171,10 @@ void GetTicketList(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_ticket_list_count;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) ticket_list_count=0x%08x, num_of_skip=0x%08x, ticket_list_pointer=0x%08x",
|
||||
am_ticket_list_count, num_of_skip, ticket_list_pointer);
|
||||
LOG_WARNING(
|
||||
Service_AM,
|
||||
"(STUBBED) ticket_list_count=0x%08x, num_of_skip=0x%08x, ticket_list_pointer=0x%08x",
|
||||
am_ticket_list_count, num_of_skip, ticket_list_pointer);
|
||||
}
|
||||
|
||||
void Init() {
|
||||
|
@ -175,7 +187,6 @@ void Init() {
|
|||
}
|
||||
|
||||
void Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
} // namespace AM
|
||||
|
|
|
@ -9,14 +9,14 @@ namespace Service {
|
|||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
|
||||
{0x10020104, FindContentInfos, "FindContentInfos"},
|
||||
{0x10030142, ListContentInfos, "ListContentInfos"},
|
||||
{0x10040102, DeleteContents, "DeleteContents"},
|
||||
{0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
|
||||
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
|
||||
{0x100900C0, nullptr, "IsDataTitleInUse"},
|
||||
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
|
||||
{0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
|
||||
{0x10020104, FindContentInfos, "FindContentInfos"},
|
||||
{0x10030142, ListContentInfos, "ListContentInfos"},
|
||||
{0x10040102, DeleteContents, "DeleteContents"},
|
||||
{0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
|
||||
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
|
||||
{0x100900C0, nullptr, "IsDataTitleInUse"},
|
||||
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
|
||||
};
|
||||
|
||||
AM_APP_Interface::AM_APP_Interface() {
|
||||
|
|
|
@ -9,61 +9,61 @@ namespace Service {
|
|||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"},
|
||||
{0x08010000, nullptr, "OpenTicket"},
|
||||
{0x08020002, nullptr, "TicketAbortInstall"},
|
||||
{0x08030002, nullptr, "TicketFinalizeInstall"},
|
||||
{0x08040100, nullptr, "InstallTitleBegin"},
|
||||
{0x08050000, nullptr, "InstallTitleAbort"},
|
||||
{0x080600C0, nullptr, "InstallTitleResume"},
|
||||
{0x08070000, nullptr, "InstallTitleAbortTMD"},
|
||||
{0x08080000, nullptr, "InstallTitleFinish"},
|
||||
{0x080A0000, nullptr, "OpenTMD"},
|
||||
{0x080B0002, nullptr, "TMDAbortInstall"},
|
||||
{0x080C0042, nullptr, "TMDFinalizeInstall"},
|
||||
{0x080E0040, nullptr, "OpenContentCreate"},
|
||||
{0x080F0002, nullptr, "ContentAbortInstall"},
|
||||
{0x08100040, nullptr, "OpenContentResume"},
|
||||
{0x08120002, nullptr, "ContentFinalizeInstall"},
|
||||
{0x08130000, nullptr, "GetTotalContents"},
|
||||
{0x08140042, nullptr, "GetContentIndexes"},
|
||||
{0x08150044, nullptr, "GetContentsInfo"},
|
||||
{0x08180042, nullptr, "GetCTCert"},
|
||||
{0x08190108, nullptr, "SetCertificates"},
|
||||
{0x081B00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"},
|
||||
{0x08010000, nullptr, "OpenTicket"},
|
||||
{0x08020002, nullptr, "TicketAbortInstall"},
|
||||
{0x08030002, nullptr, "TicketFinalizeInstall"},
|
||||
{0x08040100, nullptr, "InstallTitleBegin"},
|
||||
{0x08050000, nullptr, "InstallTitleAbort"},
|
||||
{0x080600C0, nullptr, "InstallTitleResume"},
|
||||
{0x08070000, nullptr, "InstallTitleAbortTMD"},
|
||||
{0x08080000, nullptr, "InstallTitleFinish"},
|
||||
{0x080A0000, nullptr, "OpenTMD"},
|
||||
{0x080B0002, nullptr, "TMDAbortInstall"},
|
||||
{0x080C0042, nullptr, "TMDFinalizeInstall"},
|
||||
{0x080E0040, nullptr, "OpenContentCreate"},
|
||||
{0x080F0002, nullptr, "ContentAbortInstall"},
|
||||
{0x08100040, nullptr, "OpenContentResume"},
|
||||
{0x08120002, nullptr, "ContentFinalizeInstall"},
|
||||
{0x08130000, nullptr, "GetTotalContents"},
|
||||
{0x08140042, nullptr, "GetContentIndexes"},
|
||||
{0x08150044, nullptr, "GetContentsInfo"},
|
||||
{0x08180042, nullptr, "GetCTCert"},
|
||||
{0x08190108, nullptr, "SetCertificates"},
|
||||
{0x081B00C2, nullptr, "InstallTitlesFinish"},
|
||||
};
|
||||
|
||||
AM_NET_Interface::AM_NET_Interface() {
|
||||
|
|
|
@ -8,29 +8,27 @@
|
|||
namespace Service {
|
||||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "GetPendingTitleCount"},
|
||||
{0x002400C2, nullptr, "GetPendingTitleList"}
|
||||
};
|
||||
const Interface::FunctionInfo FunctionTable[] = {{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "GetPendingTitleCount"},
|
||||
{0x002400C2, nullptr, "GetPendingTitleList"}};
|
||||
|
||||
AM_SYS_Interface::AM_SYS_Interface() {
|
||||
Register(FunctionTable);
|
||||
|
|
|
@ -8,42 +8,40 @@
|
|||
namespace Service {
|
||||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"}
|
||||
};
|
||||
const Interface::FunctionInfo FunctionTable[] = {{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"}};
|
||||
|
||||
AM_U_Interface::AM_U_Interface() {
|
||||
Register(FunctionTable);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/hle/applets/applet.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/apt/apt.h"
|
||||
#include "core/hle/service/apt/apt_a.h"
|
||||
#include "core/hle/service/apt/apt_s.h"
|
||||
|
@ -15,6 +14,7 @@
|
|||
#include "core/hle/service/apt/bcfnt/bcfnt.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/ptm/ptm.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
|
@ -30,7 +30,7 @@ static bool shared_font_relocated = false;
|
|||
|
||||
static Kernel::SharedPtr<Kernel::Mutex> lock;
|
||||
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
|
||||
static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
|
||||
static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
|
||||
|
||||
static u32 cpu_percent; ///< CPU time available to the running application
|
||||
|
||||
|
@ -51,7 +51,7 @@ void SendParameter(const MessageParameter& parameter) {
|
|||
void Initialize(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 app_id = cmd_buff[1];
|
||||
u32 flags = cmd_buff[2];
|
||||
u32 flags = cmd_buff[2];
|
||||
|
||||
cmd_buff[2] = IPC::CopyHandleDesc(2);
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
|
||||
|
@ -75,20 +75,24 @@ void GetSharedFont(Service::Interface* self) {
|
|||
if (!shared_font_mem) {
|
||||
LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds");
|
||||
cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
|
||||
cmd_buff[1] = -1; // TODO: Find the right error code
|
||||
cmd_buff[1] = -1; // TODO: Find the right error code
|
||||
return;
|
||||
}
|
||||
|
||||
// The shared font has to be relocated to the new address before being passed to the application.
|
||||
VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
|
||||
// The shared font has to be relocated to the new address before being passed to the
|
||||
// application.
|
||||
VAddr target_address =
|
||||
Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
|
||||
if (!shared_font_relocated) {
|
||||
BCFNT::RelocateSharedFont(shared_font_mem, target_address);
|
||||
shared_font_relocated = true;
|
||||
}
|
||||
cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
// Since the SharedMemory interface doesn't provide the address at which the memory was allocated,
|
||||
// the real APT service calculates this address by scanning the entire address space (using svcQueryMemory)
|
||||
// Since the SharedMemory interface doesn't provide the address at which the memory was
|
||||
// allocated,
|
||||
// the real APT service calculates this address by scanning the entire address space (using
|
||||
// svcQueryMemory)
|
||||
// and searches for an allocation of the same size as the Shared Font.
|
||||
cmd_buff[2] = target_address;
|
||||
cmd_buff[3] = IPC::CopyHandleDesc();
|
||||
|
@ -112,18 +116,19 @@ void GetLockHandle(Service::Interface* self) {
|
|||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable.
|
||||
cmd_buff[3] = 0; // Least significant bit = power button state
|
||||
cmd_buff[3] = 0; // Least significant bit = power button state
|
||||
cmd_buff[4] = IPC::CopyHandleDesc();
|
||||
cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom();
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5], applet_attributes);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5],
|
||||
applet_attributes);
|
||||
}
|
||||
|
||||
void Enable(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 attributes = cmd_buff[1];
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
parameter_event->Signal(); // Let the application know that it has been started
|
||||
parameter_event->Signal(); // Let the application know that it has been started
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
|
||||
}
|
||||
|
||||
|
@ -133,7 +138,7 @@ void GetAppletManInfo(Service::Interface* self) {
|
|||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 0;
|
||||
cmd_buff[3] = 0;
|
||||
cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
|
||||
cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
|
||||
cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
|
||||
|
@ -159,23 +164,24 @@ void IsRegistered(Service::Interface* self) {
|
|||
void InquireNotification(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 app_id = cmd_buff[1];
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
|
||||
}
|
||||
|
||||
void SendParameter(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 src_app_id = cmd_buff[1];
|
||||
u32 dst_app_id = cmd_buff[2];
|
||||
u32 signal_type = cmd_buff[3];
|
||||
u32 buffer_size = cmd_buff[4];
|
||||
u32 value = cmd_buff[5];
|
||||
u32 handle = cmd_buff[6];
|
||||
u32 size = cmd_buff[7];
|
||||
u32 buffer = cmd_buff[8];
|
||||
u32 src_app_id = cmd_buff[1];
|
||||
u32 dst_app_id = cmd_buff[2];
|
||||
u32 signal_type = cmd_buff[3];
|
||||
u32 buffer_size = cmd_buff[4];
|
||||
u32 value = cmd_buff[5];
|
||||
u32 handle = cmd_buff[6];
|
||||
u32 size = cmd_buff[7];
|
||||
u32 buffer = cmd_buff[8];
|
||||
|
||||
std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
|
||||
std::shared_ptr<HLE::Applets::Applet> dest_applet =
|
||||
HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
|
||||
|
||||
if (dest_applet == nullptr) {
|
||||
LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
|
||||
|
@ -193,9 +199,11 @@ void SendParameter(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
|
||||
"buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
|
||||
src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
|
||||
LOG_WARNING(
|
||||
Service_APT,
|
||||
"(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
|
||||
"buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
|
||||
src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
|
||||
}
|
||||
|
||||
void ReceiveParameter(Service::Interface* self) {
|
||||
|
@ -206,7 +214,7 @@ void ReceiveParameter(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = next_parameter.sender_id;
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
|
||||
cmd_buff[5] = 0x10;
|
||||
cmd_buff[6] = 0;
|
||||
|
@ -228,7 +236,7 @@ void GlanceParameter(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = next_parameter.sender_id;
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
|
||||
cmd_buff[5] = 0x10;
|
||||
cmd_buff[6] = 0;
|
||||
|
@ -237,32 +245,34 @@ void GlanceParameter(Service::Interface* self) {
|
|||
cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
|
||||
cmd_buff[8] = buffer;
|
||||
|
||||
Memory::WriteBlock(buffer, next_parameter.buffer.data(), std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size()));
|
||||
Memory::WriteBlock(buffer, next_parameter.buffer.data(),
|
||||
std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size()));
|
||||
|
||||
LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
|
||||
}
|
||||
|
||||
void CancelParameter(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 flag1 = cmd_buff[1];
|
||||
u32 unk = cmd_buff[2];
|
||||
u32 flag2 = cmd_buff[3];
|
||||
u32 flag1 = cmd_buff[1];
|
||||
u32 unk = cmd_buff[2];
|
||||
u32 flag2 = cmd_buff[3];
|
||||
u32 app_id = cmd_buff[4];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 1; // Set to Success
|
||||
cmd_buff[2] = 1; // Set to Success
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X",
|
||||
flag1, unk, flag2, app_id);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", flag1,
|
||||
unk, flag2, app_id);
|
||||
}
|
||||
|
||||
void PrepareToStartApplication(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 title_info1 = cmd_buff[1];
|
||||
u32 title_info2 = cmd_buff[2];
|
||||
u32 title_info3 = cmd_buff[3];
|
||||
u32 title_info4 = cmd_buff[4];
|
||||
u32 flags = cmd_buff[5];
|
||||
u32 title_info1 = cmd_buff[1];
|
||||
u32 title_info2 = cmd_buff[2];
|
||||
u32 title_info3 = cmd_buff[3];
|
||||
u32 title_info4 = cmd_buff[4];
|
||||
u32 flags = cmd_buff[5];
|
||||
|
||||
if (flags & 0x00000100) {
|
||||
unknown_ns_state_field = 1;
|
||||
|
@ -270,25 +280,28 @@ void PrepareToStartApplication(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
|
||||
"title_info4=0x%08X, flags=0x%08X", title_info1, title_info2, title_info3, title_info4, flags);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
|
||||
"title_info4=0x%08X, flags=0x%08X",
|
||||
title_info1, title_info2, title_info3, title_info4, flags);
|
||||
}
|
||||
|
||||
void StartApplication(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 buffer1_size = cmd_buff[1];
|
||||
u32 buffer2_size = cmd_buff[2];
|
||||
u32 flag = cmd_buff[3];
|
||||
u32 size1 = cmd_buff[4];
|
||||
u32 buffer1_ptr = cmd_buff[5];
|
||||
u32 size2 = cmd_buff[6];
|
||||
u32 buffer2_ptr = cmd_buff[7];
|
||||
u32 flag = cmd_buff[3];
|
||||
u32 size1 = cmd_buff[4];
|
||||
u32 buffer1_ptr = cmd_buff[5];
|
||||
u32 size2 = cmd_buff[6];
|
||||
u32 buffer2_ptr = cmd_buff[7];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
|
||||
"size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
|
||||
buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
|
||||
"size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
|
||||
buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
|
||||
}
|
||||
|
||||
void AppletUtility(Service::Interface* self) {
|
||||
|
@ -303,14 +316,15 @@ void AppletUtility(Service::Interface* self) {
|
|||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
|
||||
"buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size,
|
||||
buffer1_addr, buffer2_addr);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
|
||||
"buffer1_addr=0x%08X, buffer2_addr=0x%08X",
|
||||
command, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr);
|
||||
}
|
||||
|
||||
void SetAppCpuTimeLimit(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 value = cmd_buff[1];
|
||||
u32 value = cmd_buff[1];
|
||||
cpu_percent = cmd_buff[2];
|
||||
|
||||
if (value != 1) {
|
||||
|
@ -393,7 +407,8 @@ void SetScreenCapPostPermission(Service::Interface* self) {
|
|||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
|
||||
screen_capture_post_permission);
|
||||
}
|
||||
|
||||
void GetScreenCapPostPermission(Service::Interface* self) {
|
||||
|
@ -402,7 +417,8 @@ void GetScreenCapPostPermission(Service::Interface* self) {
|
|||
cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = static_cast<u32>(screen_capture_post_permission);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
|
||||
screen_capture_post_permission);
|
||||
}
|
||||
|
||||
void GetAppletInfo(Service::Interface* self) {
|
||||
|
@ -418,7 +434,8 @@ void GetAppletInfo(Service::Interface* self) {
|
|||
cmd_buff[7] = 0; // Applet Attributes
|
||||
} else {
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet,
|
||||
ErrorSummary::NotFound, ErrorLevel::Status).raw;
|
||||
ErrorSummary::NotFound, ErrorLevel::Status)
|
||||
.raw;
|
||||
}
|
||||
LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id);
|
||||
}
|
||||
|
@ -429,11 +446,15 @@ void GetStartupArgument(Service::Interface* self) {
|
|||
StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(cmd_buff[2]);
|
||||
|
||||
if (parameter_size >= 0x300) {
|
||||
LOG_ERROR(Service_APT, "Parameter size is outside the valid range (capped to 0x300): parameter_size=0x%08x", parameter_size);
|
||||
LOG_ERROR(
|
||||
Service_APT,
|
||||
"Parameter size is outside the valid range (capped to 0x300): parameter_size=0x%08x",
|
||||
parameter_size);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_WARNING(Service_APT,"(stubbed) called startup_argument_type=%u , parameter_size=0x%08x , parameter_value=0x%08x",
|
||||
LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x , "
|
||||
"parameter_value=0x%08x",
|
||||
startup_argument_type, parameter_size, Memory::Read32(cmd_buff[41]));
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
@ -484,8 +505,10 @@ void Init() {
|
|||
if (file.IsOpen()) {
|
||||
// Create shared font memory object
|
||||
using Kernel::MemoryPermission;
|
||||
shared_font_mem = Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
|
||||
shared_font_mem =
|
||||
Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read, 0,
|
||||
Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
|
||||
// Read shared font data
|
||||
file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
|
||||
} else {
|
||||
|
@ -497,7 +520,8 @@ void Init() {
|
|||
|
||||
cpu_percent = 0;
|
||||
unknown_ns_state_field = 0;
|
||||
screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
|
||||
screen_capture_post_permission =
|
||||
ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
|
||||
|
||||
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
|
||||
notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification");
|
||||
|
|
|
@ -46,58 +46,58 @@ static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has i
|
|||
|
||||
/// Signals used by APT functions
|
||||
enum class SignalType : u32 {
|
||||
None = 0x0,
|
||||
AppJustStarted = 0x1,
|
||||
None = 0x0,
|
||||
AppJustStarted = 0x1,
|
||||
LibAppJustStarted = 0x2,
|
||||
LibAppFinished = 0x3,
|
||||
LibAppClosed = 0xA,
|
||||
ReturningToApp = 0xB,
|
||||
ExitingApp = 0xC,
|
||||
LibAppFinished = 0x3,
|
||||
LibAppClosed = 0xA,
|
||||
ReturningToApp = 0xB,
|
||||
ExitingApp = 0xC,
|
||||
};
|
||||
|
||||
/// App Id's used by APT functions
|
||||
enum class AppletId : u32 {
|
||||
HomeMenu = 0x101,
|
||||
AlternateMenu = 0x103,
|
||||
Camera = 0x110,
|
||||
FriendsList = 0x112,
|
||||
GameNotes = 0x113,
|
||||
InternetBrowser = 0x114,
|
||||
InstructionManual = 0x115,
|
||||
Notifications = 0x116,
|
||||
Miiverse = 0x117,
|
||||
MiiversePost = 0x118,
|
||||
AmiiboSettings = 0x119,
|
||||
SoftwareKeyboard1 = 0x201,
|
||||
Ed1 = 0x202,
|
||||
PnoteApp = 0x204,
|
||||
SnoteApp = 0x205,
|
||||
Error = 0x206,
|
||||
Mint = 0x207,
|
||||
Extrapad = 0x208,
|
||||
Memolib = 0x209,
|
||||
Application = 0x300,
|
||||
AnyLibraryApplet = 0x400,
|
||||
SoftwareKeyboard2 = 0x401,
|
||||
Ed2 = 0x402,
|
||||
PnoteApp2 = 0x404,
|
||||
SnoteApp2 = 0x405,
|
||||
Error2 = 0x406,
|
||||
Mint2 = 0x407,
|
||||
Extrapad2 = 0x408,
|
||||
Memolib2 = 0x409,
|
||||
HomeMenu = 0x101,
|
||||
AlternateMenu = 0x103,
|
||||
Camera = 0x110,
|
||||
FriendsList = 0x112,
|
||||
GameNotes = 0x113,
|
||||
InternetBrowser = 0x114,
|
||||
InstructionManual = 0x115,
|
||||
Notifications = 0x116,
|
||||
Miiverse = 0x117,
|
||||
MiiversePost = 0x118,
|
||||
AmiiboSettings = 0x119,
|
||||
SoftwareKeyboard1 = 0x201,
|
||||
Ed1 = 0x202,
|
||||
PnoteApp = 0x204,
|
||||
SnoteApp = 0x205,
|
||||
Error = 0x206,
|
||||
Mint = 0x207,
|
||||
Extrapad = 0x208,
|
||||
Memolib = 0x209,
|
||||
Application = 0x300,
|
||||
AnyLibraryApplet = 0x400,
|
||||
SoftwareKeyboard2 = 0x401,
|
||||
Ed2 = 0x402,
|
||||
PnoteApp2 = 0x404,
|
||||
SnoteApp2 = 0x405,
|
||||
Error2 = 0x406,
|
||||
Mint2 = 0x407,
|
||||
Extrapad2 = 0x408,
|
||||
Memolib2 = 0x409,
|
||||
};
|
||||
|
||||
enum class StartupArgumentType : u32 {
|
||||
OtherApp = 0,
|
||||
Restart = 1,
|
||||
OtherApp = 0,
|
||||
Restart = 1,
|
||||
OtherMedia = 2,
|
||||
};
|
||||
|
||||
enum class ScreencapPostPermission : u32 {
|
||||
CleanThePermission = 0, //TODO(JamePeng): verify what "zero" means
|
||||
NoExplicitSetting = 1,
|
||||
EnableScreenshotPostingToMiiverse = 2,
|
||||
CleanThePermission = 0, // TODO(JamePeng): verify what "zero" means
|
||||
NoExplicitSetting = 1,
|
||||
EnableScreenshotPostingToMiiverse = 2,
|
||||
DisableScreenshotPostingToMiiverse = 3
|
||||
};
|
||||
|
||||
|
@ -182,9 +182,12 @@ void GetAppletManInfo(Service::Interface* self);
|
|||
void GetAppletInfo(Service::Interface* self);
|
||||
|
||||
/**
|
||||
* APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet.
|
||||
* An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu uses this
|
||||
* command to determine when the launched process is running and to determine when to stop using GSP etc,
|
||||
* APT::IsRegistered service function. This returns whether the specified AppID is registered with
|
||||
* NS yet.
|
||||
* An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu
|
||||
* uses this
|
||||
* command to determine when the launched process is running and to determine when to stop using GSP
|
||||
* etc,
|
||||
* while displaying the "Nintendo 3DS" loading screen.
|
||||
* Inputs:
|
||||
* 1 : AppID
|
||||
|
@ -260,9 +263,11 @@ void GlanceParameter(Service::Interface* self);
|
|||
* clears the flag which indicates that parameter data is available
|
||||
* (same flag cleared by APT:ReceiveParameter).
|
||||
* Inputs:
|
||||
* 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS state.
|
||||
* 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS
|
||||
* state.
|
||||
* 2 : Unknown, this is the same as the first unknown field returned by APT:ReceiveParameter.
|
||||
* 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS state.
|
||||
* 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS
|
||||
* state.
|
||||
* 4 : AppID
|
||||
* Outputs:
|
||||
* 0 : Return header
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue