diff options
Diffstat (limited to 'src/core')
128 files changed, 2052 insertions, 1002 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5caaee47..057b8ca0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -36,20 +36,29 @@ set(SRCS hle/kernel/shared_memory.cpp hle/kernel/thread.cpp hle/kernel/timer.cpp + hle/kernel/vm_manager.cpp hle/service/ac_u.cpp hle/service/act_u.cpp - hle/service/am_app.cpp - hle/service/am_net.cpp - hle/service/am_sys.cpp + hle/service/am/am.cpp + hle/service/am/am_app.cpp + hle/service/am/am_net.cpp + hle/service/am/am_sys.cpp + hle/service/am/am_u.cpp hle/service/apt/apt.cpp hle/service/apt/apt_a.cpp hle/service/apt/apt_s.cpp hle/service/apt/apt_u.cpp - hle/service/boss_p.cpp - hle/service/boss_u.cpp - hle/service/cam_u.cpp - hle/service/cecd_s.cpp - hle/service/cecd_u.cpp + hle/service/boss/boss.cpp + hle/service/boss/boss_p.cpp + hle/service/boss/boss_u.cpp + hle/service/cam/cam.cpp + hle/service/cam/cam_c.cpp + hle/service/cam/cam_q.cpp + hle/service/cam/cam_s.cpp + hle/service/cam/cam_u.cpp + hle/service/cecd/cecd.cpp + hle/service/cecd/cecd_s.cpp + hle/service/cecd/cecd_u.cpp hle/service/cfg/cfg.cpp hle/service/cfg/cfg_i.cpp hle/service/cfg/cfg_s.cpp @@ -57,8 +66,9 @@ set(SRCS hle/service/csnd_snd.cpp hle/service/dsp_dsp.cpp hle/service/err_f.cpp - hle/service/frd_a.cpp - hle/service/frd_u.cpp + hle/service/frd/frd.cpp + hle/service/frd/frd_a.cpp + hle/service/frd/frd_u.cpp hle/service/fs/archive.cpp hle/service/fs/fs_user.cpp hle/service/gsp_gpu.cpp @@ -74,10 +84,13 @@ set(SRCS hle/service/ldr_ro.cpp hle/service/mic_u.cpp hle/service/ndm_u.cpp - hle/service/news_s.cpp - hle/service/news_u.cpp - hle/service/nim_aoc.cpp - hle/service/nim_u.cpp + hle/service/news/news.cpp + hle/service/news/news_s.cpp + hle/service/news/news_u.cpp + hle/service/nim/nim.cpp + hle/service/nim/nim_aoc.cpp + hle/service/nim/nim_s.cpp + hle/service/nim/nim_u.cpp hle/service/ns_s.cpp hle/service/nwm_uds.cpp hle/service/pm_app.cpp @@ -116,7 +129,6 @@ set(HEADERS arm/dyncom/arm_dyncom_thumb.h arm/skyeye_common/arm_regformat.h arm/skyeye_common/armdefs.h - arm/skyeye_common/armemu.h arm/skyeye_common/armmmu.h arm/skyeye_common/vfp/asm_vfp.h arm/skyeye_common/vfp/vfp.h @@ -148,21 +160,30 @@ set(HEADERS hle/kernel/shared_memory.h hle/kernel/thread.h hle/kernel/timer.h + hle/kernel/vm_manager.h hle/result.h hle/service/ac_u.h hle/service/act_u.h - hle/service/am_app.h - hle/service/am_net.h - hle/service/am_sys.h + hle/service/am/am.h + hle/service/am/am_app.h + hle/service/am/am_net.h + hle/service/am/am_sys.h + hle/service/am/am_u.h hle/service/apt/apt.h hle/service/apt/apt_a.h hle/service/apt/apt_s.h hle/service/apt/apt_u.h - hle/service/boss_p.h - hle/service/boss_u.h - hle/service/cam_u.h - hle/service/cecd_s.h - hle/service/cecd_u.h + hle/service/boss/boss.h + hle/service/boss/boss_p.h + hle/service/boss/boss_u.h + hle/service/cam/cam.h + hle/service/cam/cam_c.h + hle/service/cam/cam_q.h + hle/service/cam/cam_s.h + hle/service/cam/cam_u.h + hle/service/cecd/cecd.h + hle/service/cecd/cecd_s.h + hle/service/cecd/cecd_u.h hle/service/cfg/cfg.h hle/service/cfg/cfg_i.h hle/service/cfg/cfg_s.h @@ -170,8 +191,9 @@ set(HEADERS hle/service/csnd_snd.h hle/service/dsp_dsp.h hle/service/err_f.h - hle/service/frd_a.h - hle/service/frd_u.h + hle/service/frd/frd.h + hle/service/frd/frd_a.h + hle/service/frd/frd_u.h hle/service/fs/archive.h hle/service/fs/fs_user.h hle/service/gsp_gpu.h @@ -187,10 +209,13 @@ set(HEADERS hle/service/ldr_ro.h hle/service/mic_u.h hle/service/ndm_u.h - hle/service/news_s.h - hle/service/news_u.h - hle/service/nim_aoc.h - hle/service/nim_u.h + hle/service/news/news.h + hle/service/news/news_s.h + hle/service/news/news_u.h + hle/service/nim/nim.h + hle/service/nim/nim_aoc.h + hle/service/nim/nim_s.h + hle/service/nim/nim_u.h hle/service/ns_s.h hle/service/nwm_uds.h hle/service/pm_app.h diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 913dc145..f6d44d85 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -813,7 +813,7 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) { // SWI return OP_SWI; } - + uint8_t bit4 = (insn >> 4) & 0x1; uint8_t cpnum = (insn >> 8) & 0xf; diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 0072ae53..529c4ac7 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -6,7 +6,7 @@ #include "common/make_unique.h" -#include "core/arm/skyeye_common/armemu.h" +#include "core/arm/skyeye_common/armdefs.h" #include "core/arm/skyeye_common/vfp/vfp.h" #include "core/arm/dyncom/arm_dyncom.h" diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index e4b5486e..b00eb49a 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -134,7 +134,7 @@ static unsigned int DPO(Immediate)(ARMul_State* cpu, unsigned int sht_oper) { unsigned int immed_8 = BITS(sht_oper, 0, 7); unsigned int rotate_imm = BITS(sht_oper, 8, 11); unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2); - if (rotate_imm == 0) + if (rotate_imm == 0) cpu->shifter_carry_out = cpu->CFlag; else cpu->shifter_carry_out = BIT(shifter_operand, 31); @@ -521,7 +521,7 @@ static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; else addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; - + virt_addr = addr; } @@ -550,7 +550,7 @@ static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, unsig if (U_BIT) addr = rn + offset_8; - else + else addr = rn - offset_8; virt_addr = addr; @@ -1306,8 +1306,8 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) + + if (inst_cream->Rd == 15) inst_base->br = INDIRECT_BRANCH; return inst_base; @@ -1350,7 +1350,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) inst_cream->shifter_operand = BITS(inst, 0, 11); inst_cream->shtop_func = get_shtop(inst); - if (inst_cream->Rd == 15) + if (inst_cream->Rd == 15) inst_base->br = INDIRECT_BRANCH; return inst_base; } @@ -3269,7 +3269,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) #define VFP_INTERPRETER_STRUCT #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" #undef VFP_INTERPRETER_STRUCT - + #define VFP_INTERPRETER_TRANS #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" #undef VFP_INTERPRETER_TRANS @@ -3478,9 +3478,9 @@ const transop_fp_t arm_instruction_trans[] = { INTERPRETER_TRANSLATE(bbl), // All the thumb instructions should be placed the end of table - INTERPRETER_TRANSLATE(b_2_thumb), - INTERPRETER_TRANSLATE(b_cond_thumb), - INTERPRETER_TRANSLATE(bl_1_thumb), + INTERPRETER_TRANSLATE(b_2_thumb), + INTERPRETER_TRANSLATE(b_cond_thumb), + INTERPRETER_TRANSLATE(bl_1_thumb), INTERPRETER_TRANSLATE(bl_2_thumb), INTERPRETER_TRANSLATE(blx_1_thumb) }; @@ -3564,17 +3564,13 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { unsigned int inst, inst_size = 4; int idx; int ret = NON_BRANCH; - int thumb = 0; int size = 0; // instruction size of basic block bb_start = top; - if (cpu->TFlag) - thumb = THUMB; - u32 phys_addr = addr; u32 pc_start = cpu->Reg[15]; - while(ret == NON_BRANCH) { + while (ret == NON_BRANCH) { inst = Memory::Read32(phys_addr & 0xFFFFFFFC); size++; @@ -3890,7 +3886,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE) #define PC (cpu->Reg[15]) - #define CHECK_EXT_INT if (!cpu->NirqSig && !(cpu->Cpsr & 0x80)) goto END; // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback // to a clunky switch statement. @@ -4343,7 +4338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { } } if (BIT(inst, 13)) { - if (cpu->Mode == USER32MODE) + if (cpu->Mode == USER32MODE) cpu->Reg[13] = ReadMemory32(cpu, addr); else cpu->Reg_usr[0] = ReadMemory32(cpu, addr); @@ -4351,7 +4346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { addr += 4; } if (BIT(inst, 14)) { - if (cpu->Mode == USER32MODE) + if (cpu->Mode == USER32MODE) cpu->Reg[14] = ReadMemory32(cpu, addr); else cpu->Reg_usr[1] = ReadMemory32(cpu, addr); @@ -5153,7 +5148,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { REV16_INST: REVSH_INST: { - + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { rev_inst* const inst_cream = (rev_inst*)inst_base->component; @@ -5726,7 +5721,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { if (do_swap) rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); - + const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); s64 result; @@ -6588,7 +6583,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { { u32 lo_val = 0; u32 hi_val = 0; - + // UHADD16 if (op2 == 0x00) { lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); @@ -6777,7 +6772,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { u16 lo_val = 0; u16 hi_val = 0; - + // UQADD16 if (op2 == 0x00) { lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF); diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp index 08b5c0b7..3e79c44c 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp @@ -184,38 +184,27 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { case 9: // LDR Rd,[PC,#imm8] *ainstr = 0xE59F0000 // base | ((tinstr & 0x0700) << (12 - 8)) // Rd - |((tinstr & 0x00FF) << (2 - 0)); // off8 + |((tinstr & 0x00FF) << (2 - 0)); // off8 break; case 10: case 11: - // TODO: Format 7 and Format 8 perform the same ARM encoding, so the following could be - // merged into a single subset, saving on the following boolean: - - if ((tinstr & (1 << 9)) == 0) { - static const ARMword subset[4] = { - 0xE7800000, // STR Rd,[Rb,Ro] - 0xE7C00000, // STRB Rd,[Rb,Ro] - 0xE7900000, // LDR Rd,[Rb,Ro] - 0xE7D00000 // LDRB Rd,[Rb,Ro] - }; - - *ainstr = subset[(tinstr & 0x0C00) >> 10] // base - |((tinstr & 0x0007) << (12 - 0)) // Rd - |((tinstr & 0x0038) << (16 - 3)) // Rb - |((tinstr & 0x01C0) >> 6); // Ro - - } else { - static const ARMword subset[4] = { + { + static const ARMword 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 & 0x0C00) >> 10] // base - |((tinstr & 0x0007) << (12 - 0)) // Rd - |((tinstr & 0x0038) << (16 - 3)) // Rb - |((tinstr & 0x01C0) >> 6); // Ro + + *ainstr = subset[(tinstr & 0xE00) >> 9] // base + |((tinstr & 0x0007) << (12 - 0)) // Rd + |((tinstr & 0x0038) << (16 - 3)) // Rb + |((tinstr & 0x01C0) >> 6); // Ro } break; @@ -285,9 +274,46 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { ? 0xE24DDF00 // SUB : 0xE28DDF00) // ADD |(tinstr & 0x007F); // off7 - } else if ((tinstr & 0x0F00) == 0x0e00) - *ainstr = 0xEF000000 | 0x180000; // base | BKPT mask - else { + } 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 + } else if ((tinstr & 0x0F00) == 0x0200) { + static const ARMword subset[4] = { + 0xE6BF0070, // SXTH + 0xE6AF0070, // SXTB + 0xE6FF0070, // UXTH + 0xE6EF0070, // UXTB + }; + + *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 + } 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 + } + } else if ((tinstr & 0x0F00) == 0x0a00) { + static const ARMword subset[3] = { + 0xE6BF0F30, // REV + 0xE6BF0FB0, // REV16 + 0xE6FF0FB0, // REVSH + }; + + *ainstr = subset[BITS(tinstr, 6, 7)] // base + | (BITS(tinstr, 0, 2) << 12) // Rd + | BITS(tinstr, 3, 5); // Rm + } else { static const ARMword subset[4] = { 0xE92D0000, // STMDB sp!,{rlist} 0xE92D4000, // STMDB sp!,{rlist,lr} @@ -301,11 +327,25 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { case 24: // STMIA case 25: // LDMIA - *ainstr = ((tinstr & (1 << 11)) // base - ? 0xE8B00000 // LDMIA - : 0xE8A00000) // STMIA - |((tinstr & 0x0700) << (16 - 8)) // Rb - |(tinstr & 0x00FF); // mask8 + if (tinstr & (1 << 11)) + { + unsigned int base = 0xE8900000; + unsigned int rn = BITS(tinstr, 8, 10); + + // Writeback + 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 + } break; case 26: // Bcc diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 680a94a3..4f7a48fa 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp @@ -17,7 +17,6 @@ #include <cstring> #include "core/arm/skyeye_common/armdefs.h" -#include "core/arm/skyeye_common/armemu.h" #include "core/arm/skyeye_common/vfp/vfp.h" /***************************************************************************\ diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index 1b078dc7..83f7f3e2 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -628,7 +628,7 @@ void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 c cpu->CP15[CP15_DATA_SYNC_BARRIER] = value; else if (opcode_2 == 5) cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value; - + } else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) { diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h index 6c89774e..a92effbb 100644 --- a/src/core/arm/skyeye_common/arm_regformat.h +++ b/src/core/arm/skyeye_common/arm_regformat.h @@ -59,6 +59,8 @@ enum { VFP_FPSID, VFP_FPSCR, VFP_FPEXC, + VFP_MVFR0, + VFP_MVFR1, // Not an actual register. // All VFP system registers should be defined above this. diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 470f9508..d2c90110 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -1,16 +1,16 @@ /* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. Copyright (C) 1994 Advanced RISC Machines Ltd. - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -262,6 +262,34 @@ enum ConditionCode { NV = 15, }; +// Flags for use with the APSR. +enum : u32 { + NBIT = (1U << 31U), + ZBIT = (1 << 30), + CBIT = (1 << 29), + VBIT = (1 << 28), + QBIT = (1 << 27), + JBIT = (1 << 24), + EBIT = (1 << 9), + ABIT = (1 << 8), + IBIT = (1 << 7), + FBIT = (1 << 6), + TBIT = (1 << 5), + + // Masks for groups of bits in the APSR. + MODEBITS = 0x1F, + INTBITS = 0x1C0, +}; + +// Values for Emulate. +enum { + STOP = 0, // Stop + CHANGEMODE = 1, // Change mode + ONCE = 2, // Execute just one iteration + RUN = 3 // Continuous execution +}; + + extern bool AddOverflow(ARMword, ARMword, ARMword); extern bool SubOverflow(ARMword, ARMword, ARMword); diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h deleted file mode 100644 index 7e096505..00000000 --- a/src/core/arm/skyeye_common/armemu.h +++ /dev/null @@ -1,47 +0,0 @@ -/* armemu.h -- ARMulator emulation macros: ARM6 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#pragma once - -#include "core/arm/skyeye_common/armdefs.h" - -// Flags for use with the APSR. -enum : u32 { - NBIT = (1U << 31U), - ZBIT = (1 << 30), - CBIT = (1 << 29), - VBIT = (1 << 28), - QBIT = (1 << 27), - JBIT = (1 << 24), - EBIT = (1 << 9), - ABIT = (1 << 8), - IBIT = (1 << 7), - FBIT = (1 << 6), - TBIT = (1 << 5), - - // Masks for groups of bits in the APSR. - MODEBITS = 0x1F, - INTBITS = 0x1C0, -}; - -// Values for Emulate. -enum { - STOP = 0, // Stop - CHANGEMODE = 1, // Change mode - ONCE = 2, // Execute just one interation - RUN = 3 // Continuous execution -}; diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index b88d4775..571d6c2f 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp @@ -33,6 +33,10 @@ unsigned VFPInit(ARMul_State* state) state->VFP[VFP_FPEXC] = 0; state->VFP[VFP_FPSCR] = 0; + // ARM11 MPCore feature register values. + state->VFP[VFP_MVFR0] = 0x11111111; + state->VFP[VFP_MVFR1] = 0; + return 0; } diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index 727350f1..acefae9b 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h @@ -22,7 +22,6 @@ #include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ -#define VFP_DEBUG_UNIMPLEMENTED(x) LOG_ERROR(Core_ARM11, "in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1); #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested\n", __FUNCTION__); #define CHECK_VFP_ENABLED #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index ccc0212a..2007d6dc 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h @@ -18,10 +18,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/* * The following code is derivative from Linux Android kernel vfp * floating point support. - * + * * Copyright (C) 2004 ARM Limited. * Written by Deep Blue Solutions Limited. * diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 3ed918a9..67fe63aa 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -1068,10 +1068,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index) #ifdef VFP_INTERPRETER_IMPL VMOVBRC_INST: { - if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { CHECK_VFP_ENABLED; - VFP_DEBUG_UNIMPLEMENTED(VMOVBRC); + vmovbrc_inst* const inst_cream = (vmovbrc_inst*)inst_base->component; + + cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(vmovbrc_inst)); @@ -1139,12 +1141,10 @@ VMRS_INST: cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; break; case 6: - /* MVFR1, VFPv3 only ? */ - LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", inst_cream->Rt); + cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1]; break; case 7: - /* MVFR0, VFPv3 only? */ - LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", inst_cream->Rt); + cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0]; break; case 8: cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; @@ -1195,10 +1195,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index) #ifdef VFP_INTERPRETER_IMPL VMOVBCR_INST: { - if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { CHECK_VFP_ENABLED; - VFP_DEBUG_UNIMPLEMENTED(VMOVBCR); + vmovbcr_inst* const inst_cream = (vmovbcr_inst*) inst_base->component; + + cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(vmovbcr_inst)); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index f70c84c3..e53c2e60 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -549,7 +549,7 @@ std::string GetScheduledEventsSummary() { const char* name = event_types[event->type].name; if (!name) name = "[unknown]"; - text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time, + text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time, (u32)(event->userdata >> 32), (u32)(event->userdata)); event = event->next; } diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 01519608..64f5b06d 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -87,7 +87,7 @@ void UnregisterAllEvents(); /// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, /// when we implement state saves. /** - * Schedules an event to run after the specified number of cycles, + * Schedules an event to run after the specified number of cycles, * with an optional parameter to be passed to the callback handler. * This must be run ONLY from within the cpu thread. * @param cycles_into_future The number of cycles after which this event will be fired diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index 38d498d0..e50c58a5 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -30,8 +30,8 @@ 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("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), + + return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str(), SDCARD_ID.c_str()); } @@ -71,7 +71,7 @@ bool ArchiveFactory_ExtSaveData::Initialize() { } ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { - std::string fullpath = GetExtSaveDataPath(mount_point, path); + std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/"; if (!FileUtil::Exists(fullpath)) { // TODO(Subv): Check error code, this one is probably wrong return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, @@ -82,8 +82,11 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons } ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { - std::string fullpath = GetExtSaveDataPath(mount_point, path); - FileUtil::CreateFullPath(fullpath); + // 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/"; + FileUtil::CreateFullPath(user_path); + FileUtil::CreateFullPath(boss_path); return RESULT_SUCCESS; } diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index c77c04e4..ef0b27bd 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h @@ -35,14 +35,14 @@ public: private: /** * This holds the full directory path for this archive, it is only set after a successful call - * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. + * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. * See GetExtSaveDataPath for the code that extracts this data from an archive path. */ std::string mount_point; }; /** - * Constructs a path to the concrete ExtData archive in the host filesystem based on the + * Constructs a path to the concrete ExtData archive in the host filesystem based on the * input Path and base mount point. * @param mount_point The base mount point of the ExtSaveData archives. * @param path The path that identifies the requested concrete ExtSaveData archive. diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index 8dff5196..a9230937 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp @@ -21,7 +21,7 @@ namespace FileSys { static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) { - return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), + return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), SYSTEM_ID.c_str(), SDCARD_ID.c_str()); } diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 23c86a72..5949cb47 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -9,11 +9,15 @@ #include "core/arm/arm_interface.h" #include "core/memory.h" #include "core/hle/hle.h" +#include "core/hle/result.h" namespace HLE { #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); + /** * HLE a function return from the current ARM11 userland process * @param res Result to return @@ -57,8 +61,11 @@ 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; - Core::g_app_core->SetReg(1, (u32)param_1); - FuncReturn(retval); + + if (retval != RESULT_INVALID.raw) { + Core::g_app_core->SetReg(1, (u32)param_1); + FuncReturn(retval); + } } template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { @@ -73,7 +80,11 @@ template<ResultCode func(u32*)> void Wrap(){ } template<ResultCode func(u32, s64)> void Wrap() { - FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); + s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw; + + if (retval != RESULT_INVALID.raw) { + FuncReturn(retval); + } } template<ResultCode func(void*, void*, u32)> void Wrap(){ diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index e45deb1c..f338f326 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -41,10 +41,7 @@ void Event::Acquire() { void Event::Signal() { signaled = true; - WakeupAllWaitingThreads(); - - HLE::Reschedule(__func__); } void Event::Clear() { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 726e4d2f..20e11da1 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -32,27 +32,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -SharedPtr<Thread> WaitObject::WakeupNextThread() { - if (waiting_threads.empty()) - return nullptr; - - auto next_thread = std::move(waiting_threads.front()); - waiting_threads.erase(waiting_threads.begin()); - - next_thread->ReleaseWaitObject(this); - - return next_thread; -} - void WaitObject::WakeupAllWaitingThreads() { - auto waiting_threads_copy = waiting_threads; + for (auto thread : waiting_threads) + thread->ResumeFromWait(); - // We use a copy because ReleaseWaitObject will remove the thread from this object's - // waiting_threads list - for (auto thread : waiting_threads_copy) - thread->ReleaseWaitObject(this); + waiting_threads.clear(); - ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!"); + HLE::Reschedule(__func__); } HandleTable::HandleTable() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a5a0f480..64595f75 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -140,12 +140,6 @@ public: */ void RemoveWaitingThread(Thread* thread); - /** - * Wake up the next thread waiting on this object - * @return Pointer to the thread that was resumed, nullptr if no threads are waiting - */ - SharedPtr<Thread> WakeupNextThread(); - /// Wake up all threads waiting on this object void WakeupAllWaitingThreads(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 6aa73df8..edb97d32 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -23,12 +23,7 @@ static void ResumeWaitingThread(Mutex* mutex) { // Reset mutex lock thread handle, nothing is waiting mutex->lock_count = 0; mutex->holding_thread = nullptr; - - // Find the next waiting thread for the mutex... - auto next_thread = mutex->WakeupNextThread(); - if (next_thread != nullptr) { - mutex->Acquire(next_thread); - } + mutex->WakeupAllWaitingThreads(); } void ReleaseThreadMutexes(Thread* thread) { @@ -94,8 +89,6 @@ void Mutex::Release() { ResumeWaitingThread(this); } } - - HLE::Reschedule(__func__); } } // namespace diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 201ec0db..1b8249c7 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -81,13 +81,13 @@ public: s32 max_timers = 0; s32 max_shared_mems = 0; s32 max_address_arbiters = 0; - + /// 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 - // 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, + // 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 /// Current memory that the processes in this category are using diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index dbb4c9b7..4b359ed0 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -42,19 +42,13 @@ void Semaphore::Acquire() { ResultVal<s32> Semaphore::Release(s32 release_count) { if (max_count - available_count < release_count) - return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, + return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); s32 previous_count = available_count; available_count += release_count; - // Notify some of the threads that the semaphore has been released - // stop once the semaphore is full again or there are no more waiting threads - while (!ShouldWait() && WakeupNextThread() != nullptr) { - Acquire(); - } - - HLE::Reschedule(__func__); + WakeupAllWaitingThreads(); return MakeResult<s32>(previous_count); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 690d33b5..4729a7fe 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,6 +13,7 @@ #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" +#include "core/arm/skyeye_common/armdefs.h" #include "core/core.h" #include "core/core_timing.h" #include "core/hle/hle.h" @@ -100,7 +101,7 @@ void Thread::Stop() { } status = THREADSTATUS_DEAD; - + WakeupAllWaitingThreads(); // Clean up any dangling references in objects that this thread was waiting for @@ -169,7 +170,7 @@ static void PriorityBoostStarvedThreads() { } } -/** +/** * Switches the CPU's active thread context to that of the specified thread * @param new_thread The thread to switch to */ @@ -193,8 +194,22 @@ static void SwitchContext(Thread* new_thread) { if (new_thread) { 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); + current_thread = new_thread; + // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun + // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire + // the requested wait object(s) before continuing. + if (new_thread->waitsynch_waited) { + // CPSR flag indicates CPU mode + bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0; + + // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM + new_thread->context.pc -= thumb_mode ? 2 : 4; + } + ready_queue.remove(new_thread->current_priority, new_thread); new_thread->status = THREADSTATUS_RUNNING; @@ -243,6 +258,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa thread->wait_set_output = wait_set_output; thread->wait_all = wait_all; thread->wait_objects = std::move(wait_objects); + thread->waitsynch_waited = true; thread->status = THREADSTATUS_WAIT_SYNCH; } @@ -268,6 +284,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { return; } + thread->waitsynch_waited = false; + if (thread->status == THREADSTATUS_WAIT_SYNCH) { thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged, ErrorLevel::Info)); @@ -288,63 +306,20 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); } -void Thread::ReleaseWaitObject(WaitObject* wait_object) { - if (status != THREADSTATUS_WAIT_SYNCH || wait_objects.empty()) { - LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); - return; - } - - // Remove this thread from the waiting object's thread list - wait_object->RemoveWaitingThread(this); - - unsigned index = 0; - bool wait_all_failed = false; // Will be set to true if any object is unavailable - - // Iterate through all waiting objects to check availability... - for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - if ((*itr)->ShouldWait()) - wait_all_failed = true; - - // The output should be the last index of wait_object - if (*itr == wait_object) - index = itr - wait_objects.begin(); - } - - // If we are waiting on all objects... - if (wait_all) { - // Resume the thread only if all are available... - if (!wait_all_failed) { - SetWaitSynchronizationResult(RESULT_SUCCESS); - SetWaitSynchronizationOutput(-1); - - ResumeFromWait(); - } - } else { - // Otherwise, resume - SetWaitSynchronizationResult(RESULT_SUCCESS); - - if (wait_set_output) - SetWaitSynchronizationOutput(index); - - ResumeFromWait(); - } -} - void Thread::ResumeFromWait() { - // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); - switch (status) { case THREADSTATUS_WAIT_SYNCH: - // Remove this thread from all other WaitObjects - for (auto wait_object : wait_objects) - wait_object->RemoveWaitingThread(this); - break; case THREADSTATUS_WAIT_ARB: case THREADSTATUS_WAIT_SLEEP: break; - case THREADSTATUS_RUNNING: + 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: @@ -353,7 +328,7 @@ void Thread::ResumeFromWait() { GetObjectId()); return; } - + ready_queue.push_back(current_priority, this); status = THREADSTATUS_READY; } @@ -415,6 +390,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); thread->owner_process = g_current_process; thread->tls_index = -1; + thread->waitsynch_waited = false; // Find the next available TLS index, and mark it as used auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; @@ -504,7 +480,7 @@ void Reschedule() { } else if (next) { LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); } - + SwitchContext(next); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 38992817..b8160bb2 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -94,12 +94,6 @@ public: * @return The thread's ID */ u32 GetThreadId() const { return thread_id; } - - /** - * Release an acquired wait object - * @param wait_object WaitObject to release - */ - void ReleaseWaitObject(WaitObject* wait_object); /** * Resumes a thread from waiting @@ -152,6 +146,8 @@ public: s32 tls_index; ///< Index of the Thread Local Storage of the thread + bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait + /// Mutexes currently held by this thread, which will be released when it exits. boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; @@ -163,12 +159,12 @@ public: std::string name; + /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. + Handle callback_handle; + private: Thread(); ~Thread() override; - - /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. - Handle callback_handle; }; /** diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 25d066bf..8aa4110a 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -88,7 +88,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { if (timer->interval_delay != 0) { // Reschedule the timer with the interval delay u64 interval_microseconds = timer->interval_delay / 1000; - CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, + CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, timer_callback_event_type, timer_handle); } } diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp new file mode 100644 index 00000000..b2dd2154 --- /dev/null +++ b/src/core/hle/kernel/vm_manager.cpp @@ -0,0 +1,245 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/vm_manager.h" +#include "core/memory_setup.h" + +namespace Kernel { + +bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { + ASSERT(base + size == next.base); + 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)) { + return false; + } + if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { + return false; + } + if (type == VMAType::MMIO && paddr + size != next.paddr) { + return false; + } + return true; +} + +VMManager::VMManager() { + Reset(); +} + +void VMManager::Reset() { + vma_map.clear(); + + // Initialize the map with a single free region covering the entire managed space. + VirtualMemoryArea initial_vma; + initial_vma.size = MAX_ADDRESS; + vma_map.emplace(initial_vma.base, initial_vma); + + UpdatePageTableForVMA(initial_vma); +} + +VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { + return std::prev(vma_map.upper_bound(target)); +} + +ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, + std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) { + ASSERT(block != nullptr); + ASSERT(offset + size <= block->size()); + + // 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; + ASSERT(final_vma.size == size); + + final_vma.type = VMAType::AllocatedMemoryBlock; + final_vma.permissions = VMAPermission::ReadWrite; + final_vma.meminfo_state = state; + final_vma.backing_block = block; + final_vma.offset = offset; + UpdatePageTableForVMA(final_vma); + + return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); +} + +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. + CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); + VirtualMemoryArea& final_vma = vma_handle->second; + ASSERT(final_vma.size == size); + + final_vma.type = VMAType::BackingMemory; + final_vma.permissions = VMAPermission::ReadWrite; + final_vma.meminfo_state = state; + final_vma.backing_memory = memory; + UpdatePageTableForVMA(final_vma); + + return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); +} + +ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) { + // 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; + ASSERT(final_vma.size == size); + + final_vma.type = VMAType::MMIO; + final_vma.permissions = VMAPermission::ReadWrite; + final_vma.meminfo_state = state; + final_vma.paddr = paddr; + UpdatePageTableForVMA(final_vma); + + return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); +} + +void VMManager::Unmap(VMAHandle vma_handle) { + VMAIter iter = StripIterConstness(vma_handle); + + VirtualMemoryArea& vma = iter->second; + vma.type = VMAType::Free; + vma.permissions = VMAPermission::None; + vma.meminfo_state = MemoryState::Free; + + vma.backing_block = nullptr; + vma.offset = 0; + vma.backing_memory = nullptr; + vma.paddr = 0; + + UpdatePageTableForVMA(vma); + + MergeAdjacent(iter); +} + +void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) { + VMAIter iter = StripIterConstness(vma_handle); + + VirtualMemoryArea& vma = iter->second; + vma.permissions = new_perms; + UpdatePageTableForVMA(vma); + + MergeAdjacent(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 +} + +ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { + ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size); + ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base); + + VMAIter vma_handle = StripIterConstness(FindVMA(base)); + if (vma_handle == vma_map.end()) { + // Target address is outside the range managed by the kernel + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5 + } + + VirtualMemoryArea& vma = vma_handle->second; + if (vma.type != VMAType::Free) { + // Region is already allocated + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, + ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5 + } + + u32 start_in_vma = base - vma.base; + u32 end_in_vma = start_in_vma + size; + + if (end_in_vma > vma.size) { + // Requested allocation doesn't fit inside VMA + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, + ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5 + } + + if (end_in_vma != vma.size) { + // Split VMA at the end of the allocated region + SplitVMA(vma_handle, end_in_vma); + } + if (start_in_vma != 0) { + // Split VMA at the start of the allocated region + vma_handle = SplitVMA(vma_handle, start_in_vma); + } + + return MakeResult<VMAIter>(vma_handle); +} + +VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) { + VirtualMemoryArea& old_vma = vma_handle->second; + VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA + + // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably + // a bug. This restriction might be removed later. + ASSERT(offset_in_vma < old_vma.size); + ASSERT(offset_in_vma > 0); + + old_vma.size = offset_in_vma; + new_vma.base += offset_in_vma; + new_vma.size -= offset_in_vma; + + switch (new_vma.type) { + case VMAType::Free: + break; + case VMAType::AllocatedMemoryBlock: + new_vma.offset += offset_in_vma; + break; + case VMAType::BackingMemory: + new_vma.backing_memory += offset_in_vma; + break; + case VMAType::MMIO: + new_vma.paddr += offset_in_vma; + break; + } + + ASSERT(old_vma.CanBeMergedWith(new_vma)); + + return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma); +} + +VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { + VMAIter next_vma = std::next(iter); + if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) { + iter->second.size += next_vma->second.size; + vma_map.erase(next_vma); + } + + if (iter != vma_map.begin()) { + VMAIter prev_vma = std::prev(iter); + if (prev_vma->second.CanBeMergedWith(iter->second)) { + prev_vma->second.size += iter->second.size; + vma_map.erase(iter); + iter = prev_vma; + } + } + + return iter; +} + +void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { + switch (vma.type) { + case VMAType::Free: + Memory::UnmapRegion(vma.base, vma.size); + break; + case VMAType::AllocatedMemoryBlock: + Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset); + break; + case VMAType::BackingMemory: + Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory); + break; + case VMAType::MMIO: + // TODO(yuriks): Add support for MMIO handlers. + Memory::MapIoRegion(vma.base, vma.size); + break; + } +} + +} diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h new file mode 100644 index 00000000..22b72460 --- /dev/null +++ b/src/core/hle/kernel/vm_manager.h @@ -0,0 +1,200 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "common/common_types.h" + +#include "core/hle/result.h" + +namespace Kernel { + +enum class VMAType : u8 { + /// VMA represents an unmapped region of the address space. + Free, + /// VMA is backed by a ref-counted allocate memory block. + AllocatedMemoryBlock, + /// VMA is backed by a raw, unmanaged pointer. + BackingMemory, + /// VMA is mapped to MMIO registers at a fixed PAddr. + MMIO, + // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP +}; + +/// Permissions for mapped memory blocks +enum class VMAPermission : u8 { + None = 0, + Read = 1, + Write = 2, + Execute = 4, + + ReadWrite = Read | Write, + ReadExecute = Read | Execute, + WriteExecute = Write | Execute, + ReadWriteExecute = Read | Write | Execute, +}; + +/// Set of values returned in MemoryInfo.state by svcQueryMemory. +enum class MemoryState : u8 { + Free = 0, + Reserved = 1, + IO = 2, + Static = 3, + Code = 4, + Private = 5, + Shared = 6, + Continuous = 7, + Aliased = 8, + Alias = 9, + AliasCode = 10, + Locked = 11, +}; + +/** + * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space + * with homogeneous attributes across its extents. In this particular implementation each VMA is + * also backed by a single host memory allocation. + */ +struct VirtualMemoryArea { + /// Virtual base address of the region. + VAddr base = 0; + /// Size of the region. + u32 size = 0; + + VMAType type = VMAType::Free; + VMAPermission permissions = VMAPermission::None; + /// Tag returned by svcQueryMemory. Not otherwise used. + MemoryState meminfo_state = MemoryState::Free; + + // Settings for type = AllocatedMemoryBlock + /// Memory block backing this VMA. + std::shared_ptr<std::vector<u8>> backing_block = nullptr; + /// Offset into the backing_memory the mapping starts from. + u32 offset = 0; + + // Settings for type = BackingMemory + /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed. + u8* backing_memory = nullptr; + + // Settings for type = MMIO + /// Physical address of the register area this VMA maps to. + PAddr paddr = 0; + + /// Tests if this area can be merged to the right with `next`. + bool CanBeMergedWith(const VirtualMemoryArea& next) const; +}; + +/** + * Manages a process' virtual addressing space. This class maintains a list of allocated and free + * regions in the address space, along with their attributes, and allows kernel clients to + * manipulate it, adjusting the page table to match. + * + * This is similar in idea and purpose to the VM manager present in operating system kernels, with + * the main difference being that it doesn't have to support swapping or memory mapping of files. + * The implementation is also simplified by not having to allocate page frames. See these articles + * about the Linux kernel for an explantion of the concept and implementation: + * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/ + * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ + */ +class VMManager { + // 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. + * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000. + */ + static const u32 MAX_ADDRESS = 0x40000000; + + /** + * A map covering the entirety of the managed address space, keyed by the `base` field of each + * VMA. It must always be modified by splitting or merging VMAs, so that the invariant + * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be + * merged when possible so that no two similar and adjacent regions exist that have not been + * merged. + */ + std::map<VAddr, VirtualMemoryArea> vma_map; + using VMAHandle = decltype(vma_map)::const_iterator; + + VMManager(); + + /// Clears the address space map, re-initializing with a single free area. + void Reset(); + + /// Finds the VMA in which the given address is included in, or `vma_map.end()`. + VMAHandle FindVMA(VAddr target) const; + + // TODO(yuriks): Should these functions actually return the handle? + + /** + * Maps part of a ref-counted block of memory at a given address. + * + * @param target The guest address to start the mapping at. + * @param block The block to be mapped. + * @param offset Offset into `block` to map from. + * @param size Size of the mapping. + * @param state MemoryState tag to attach to the VMA. + */ + ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, + u32 offset, u32 size, MemoryState state); + + /** + * Maps an unmanaged host memory pointer at a given address. + * + * @param target The guest address to start the mapping at. + * @param memory The memory to be mapped. + * @param size Size of the mapping. + * @param state MemoryState tag to attach to the VMA. + */ + ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state); + + /** + * Maps a memory-mapped IO region at a given address. + * + * @param target The guest address to start the mapping at. + * @param paddr The physical address where the registers are present. + * @param size Size of the mapping. + * @param state MemoryState tag to attach to the VMA. + */ + ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state); + + /// Unmaps the given VMA. + void Unmap(VMAHandle vma); + + /// Changes the permissions of the given VMA. + void Reprotect(VMAHandle vma, VMAPermission new_perms); + +private: + using VMAIter = decltype(vma_map)::iterator; + + /// Converts a VMAHandle to a mutable VMAIter. + VMAIter StripIterConstness(const VMAHandle& iter); + + /** + * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing + * the appropriate error checking. + */ + ResultVal<VMAIter> CarveVMA(VAddr base, u32 size); + + /** + * Splits a VMA in two, at the specified offset. + * @returns the right side of the split, with the original iterator becoming the left side. + */ + VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma); + + /** + * Checks for and merges the specified VMA with adjacent ones if possible. + * @returns the merged VMA or the original if no merging was possible. + */ + VMAIter MergeAdjacent(VMAIter vma); + + /// Updates the pages corresponding to this VMA so they match the VMA's attributes. + void UpdatePageTableForVMA(const VirtualMemoryArea& vma); +}; + +} diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp new file mode 100644 index 00000000..57dc1ece --- /dev/null +++ b/src/core/hle/service/am/am.cpp @@ -0,0 +1,55 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.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/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" + +namespace Service { +namespace AM { + +void TitleIDListGetTotal(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 media_type = cmd_buff[1] & 0xFF; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + + LOG_WARNING(Service_AM, "(STUBBED) media_type %u", media_type); +} + +void GetTitleIDList(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 num_titles = cmd_buff[1]; + u32 media_type = cmd_buff[2] & 0xFF; + u32 addr = cmd_buff[4]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + + LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); +} + +void Init() { + using namespace Kernel; + + AddService(new AM_APP_Interface); + AddService(new AM_NET_Interface); + AddService(new AM_SYS_Interface); +} + +void Shutdown() { + +} + +} // namespace AM + +} // namespace Service diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h new file mode 100644 index 00000000..063b8bd0 --- /dev/null +++ b/src/core/hle/service/am/am.h @@ -0,0 +1,47 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +/** + * AM::TitleIDListGetTotal service function + * Gets the number of installed titles in the requested media type + * Inputs: + * 0 : Command header (0x00010040) + * 1 : Media type to load the titles from + * Outputs: + * 1 : Result, 0 on success, otherwise error code + * 2 : The number of titles in the requested media type + */ +void TitleIDListGetTotal(Service::Interface* self); + +/** + * AM::GetTitleIDList service function + * Loads information about the desired number of titles from the desired media type into an array + * Inputs: + * 0 : Command header (0x00020082) + * 1 : The maximum number of titles to load + * 2 : Media type to load the titles from + * 3 : Descriptor of the output buffer pointer + * 4 : Address of the output buffer + * Outputs: + * 1 : Result, 0 on success, otherwise error code + * 2 : The number of titles loaded from the requested media type + */ +void GetTitleIDList(Service::Interface* self); + +/// Initialize AM service +void Init(); + +/// Shutdown AM service +void Shutdown(); + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp new file mode 100644 index 00000000..c6fc81bc --- /dev/null +++ b/src/core/hle/service/am/am_app.cpp @@ -0,0 +1,20 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_app.h" + +namespace Service { +namespace AM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +AM_APP_Interface::AM_APP_Interface() { + //Register(FunctionTable); +} + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h new file mode 100644 index 00000000..fd6017d1 --- /dev/null +++ b/src/core/hle/service/am/am_app.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_APP_Interface : public Service::Interface { +public: + AM_APP_Interface(); + + std::string GetPortName() const override { + return "am:app"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am/am_net.cpp index ba2a499f..b1af0e9d 100644 --- a/src/core/hle/service/am_net.cpp +++ b/src/core/hle/service/am/am_net.cpp @@ -3,12 +3,11 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/am_net.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_net.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_NET - -namespace AM_NET { +namespace Service { +namespace AM { const Interface::FunctionInfo FunctionTable[] = { {0x08010000, nullptr, "OpenTicket"}, @@ -33,11 +32,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x081B00C2, nullptr, "InstallTitlesFinish"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +AM_NET_Interface::AM_NET_Interface() { Register(FunctionTable); } -} // namespace +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h new file mode 100644 index 00000000..25d2c3f2 --- /dev/null +++ b/src/core/hle/service/am/am_net.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_NET_Interface : public Service::Interface { +public: + AM_NET_Interface(); + + std::string GetPortName() const override { + return "am:net"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp new file mode 100644 index 00000000..864fc14d --- /dev/null +++ b/src/core/hle/service/am/am_sys.cpp @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_sys.h" + +namespace Service { +namespace AM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, + {0x00020082, GetTitleIDList, "GetTitleIDList"}, +}; + +AM_SYS_Interface::AM_SYS_Interface() { + Register(FunctionTable); +} + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h new file mode 100644 index 00000000..b114f1d3 --- /dev/null +++ b/src/core/hle/service/am/am_sys.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_SYS_Interface : public Service::Interface { +public: + AM_SYS_Interface(); + + std::string GetPortName() const override { + return "am:sys"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp new file mode 100644 index 00000000..6bf84b36 --- /dev/null +++ b/src/core/hle/service/am/am_u.cpp @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_u.h" + +namespace Service { +namespace AM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, + {0x00020082, GetTitleIDList, "GetTitleIDList"}, +}; + +AM_U_Interface::AM_U_Interface() { + Register(FunctionTable); +} + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h new file mode 100644 index 00000000..3b2454b6 --- /dev/null +++ b/src/core/hle/service/am/am_u.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_U_Interface : public Service::Interface { +public: + AM_U_Interface(); + + std::string GetPortName() const override { + return "am:u"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am_app.cpp b/src/core/hle/service/am_app.cpp deleted file mode 100644 index 684b753f..00000000 --- a/src/core/hle/service/am_app.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/am_app.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_APP - -namespace AM_APP { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/am_app.h b/src/core/hle/service/am_app.h deleted file mode 100644 index 50dc2f5a..00000000 --- a/src/core/hle/service/am_app.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_APP - -namespace AM_APP { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "am:app"; - } -}; - -} // namespace diff --git a/src/core/hle/service/am_net.h b/src/core/hle/service/am_net.h deleted file mode 100644 index 616c33ee..00000000 --- a/src/core/hle/service/am_net.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_NET - -namespace AM_NET { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "am:net"; - } -}; - -} // namespace diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp deleted file mode 100644 index f9e3fe4b..00000000 --- a/src/core/hle/service/am_sys.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" - -#include "core/hle/hle.h" -#include "core/hle/service/am_sys.h" - -namespace AM_SYS { - -/** - * Gets the number of installed titles in the requested media type - * Inputs: - * 0: Command header (0x00010040) - * 1: Media type to load the titles from - * Outputs: - * 1: Result, 0 on success, otherwise error code - * 2: The number of titles in the requested media type - */ -static void TitleIDListGetTotal(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 media_type = cmd_buff[1] & 0xFF; - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; - LOG_WARNING(Service_CFG, "(STUBBED) media_type %u", media_type); -} - -/** - * Loads information about the desired number of titles from the desired media type into an array - * Inputs: - * 0: Command header (0x00020082) - * 1: The maximum number of titles to load - * 2: Media type to load the titles from - * 3: Descriptor of the output buffer pointer - * 4: Address of the output buffer - * Outputs: - * 1: Result, 0 on success, otherwise error code - * 2: The number of titles loaded from the requested media type - */ -static void GetTitleIDList(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 num_titles = cmd_buff[1]; - u32 media_type = cmd_buff[2] & 0xFF; - u32 addr = cmd_buff[4]; - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; - LOG_WARNING(Service_CFG, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, - {0x00020082, GetTitleIDList, "GetTitleIDList"}, -}; - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/am_sys.h b/src/core/hle/service/am_sys.h deleted file mode 100644 index bb6178a4..00000000 --- a/src/core/hle/service/am_sys.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_SYS - -namespace AM_SYS { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "am:sys"; - } -}; - -} // namespace diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 3fd4cfb0..5d14f393 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -151,7 +151,7 @@ void SendParameter(Service::Interface* self) { u32 handle = cmd_buff[6]; u32 size = cmd_buff[7]; u32 in_param_buffer_ptr = cmd_buff[8]; - + cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," @@ -283,7 +283,7 @@ void Init() { AddService(new APT_A_Interface); AddService(new APT_S_Interface); AddService(new APT_U_Interface); - + // Load the shared system font (if available). // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index e7fa3932..a03e1712 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -63,7 +63,7 @@ void Initialize(Service::Interface* self); * 4 : Handle to shared font memory */ void GetSharedFont(Service::Interface* self); - + /** * APT::NotifyToWait service function * Inputs: @@ -88,7 +88,7 @@ void Enable(Service::Interface* self); * 4 : Home Menu AppId * 5 : AppID of currently active app */ -void GetAppletManInfo(Service::Interface* self); +void GetAppletManInfo(Service::Interface* self); /** * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. @@ -100,14 +100,14 @@ void GetAppletManInfo(Service::Interface* self); * Outputs: * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output, 0 = not registered, 1 = registered. + * 2 : Output, 0 = not registered, 1 = registered. */ void IsRegistered(Service::Interface* self); void InquireNotification(Service::Interface* self); /** - * APT::SendParameter service function. This sets the parameter data state. + * APT::SendParameter service function. This sets the parameter data state. * Inputs: * 1 : Source AppID * 2 : Destination AppID diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp new file mode 100644 index 00000000..d38140f1 --- /dev/null +++ b/src/core/hle/service/boss/boss.cpp @@ -0,0 +1,29 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/service.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/boss/boss_p.h" +#include "core/hle/service/boss/boss_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace BOSS { + +void Init() { + using namespace Kernel; + + AddService(new BOSS_P_Interface); + AddService(new BOSS_U_Interface); +} + +void Shutdown() { +} + +} // namespace BOSS + +} // namespace Service diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h new file mode 100644 index 00000000..a6942ada --- /dev/null +++ b/src/core/hle/service/boss/boss.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace BOSS { + +/// Initialize BOSS service(s) +void Init(); + +/// Shutdown BOSS service(s) +void Shutdown(); + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp new file mode 100644 index 00000000..089f5f18 --- /dev/null +++ b/src/core/hle/service/boss/boss_p.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/boss/boss_p.h" + +namespace Service { +namespace BOSS { + +// Empty arrays are illegal -- commented out until an entry is added. +// const Interface::FunctionInfo FunctionTable[] = { }; + +BOSS_P_Interface::BOSS_P_Interface() { + //Register(FunctionTable); +} + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_p.h b/src/core/hle/service/boss/boss_p.h new file mode 100644 index 00000000..32112c25 --- /dev/null +++ b/src/core/hle/service/boss/boss_p.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace BOSS { + +class BOSS_P_Interface : public Service::Interface { +public: + BOSS_P_Interface(); + + std::string GetPortName() const override { + return "boss:P"; + } +}; + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp new file mode 100644 index 00000000..ed978b96 --- /dev/null +++ b/src/core/hle/service/boss/boss_u.cpp @@ -0,0 +1,21 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/boss/boss_u.h" + +namespace Service { +namespace BOSS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00020100, nullptr, "GetStorageInfo"}, +}; + +BOSS_U_Interface::BOSS_U_Interface() { + Register(FunctionTable); +} + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_u.h b/src/core/hle/service/boss/boss_u.h new file mode 100644 index 00000000..d047d8cf --- /dev/null +++ b/src/core/hle/service/boss/boss_u.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace BOSS { + +class BOSS_U_Interface : public Service::Interface { +public: + BOSS_U_Interface(); + + std::string GetPortName() const override { + return "boss:U"; + } +}; + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss_p.cpp b/src/core/hle/service/boss_p.cpp deleted file mode 100644 index 8280830e..00000000 --- a/src/core/hle/service/boss_p.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/boss_p.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_P - -namespace BOSS_P { - -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/boss_p.h b/src/core/hle/service/boss_p.h deleted file mode 100644 index 71f1e746..00000000 --- a/src/core/hle/service/boss_p.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_P - -namespace BOSS_P { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "boss:P"; - } -}; - -} // namespace diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp deleted file mode 100644 index 2c322bdf..00000000 --- a/src/core/hle/service/boss_u.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/boss_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_U - -namespace BOSS_U { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00020100, nullptr, "GetStorageInfo"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h deleted file mode 100644 index 2668f2df..00000000 --- a/src/core/hle/service/boss_u.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_U - -namespace BOSS_U { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "boss:U"; - } -}; - -} // namespace diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp new file mode 100644 index 00000000..4f34b699 --- /dev/null +++ b/src/core/hle/service/cam/cam.cpp @@ -0,0 +1,35 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_c.h" +#include "core/hle/service/cam/cam_q.h" +#include "core/hle/service/cam/cam_s.h" +#include "core/hle/service/cam/cam_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace CAM { + +void Init() { + using namespace Kernel; + + AddService(new CAM_C_Interface); + AddService(new CAM_Q_Interface); + AddService(new CAM_S_Interface); + AddService(new CAM_U_Interface); +} + +void Shutdown() { +} + +} // namespace CAM + +} // namespace Service diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h new file mode 100644 index 00000000..edd52484 --- /dev/null +++ b/src/core/hle/service/cam/cam.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +/// Initialize CAM service(s) +void Init(); + +/// Shutdown CAM service(s) +void Shutdown(); + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp new file mode 100644 index 00000000..d35adcb9 --- /dev/null +++ b/src/core/hle/service/cam/cam_c.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_c.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_C_Interface::CAM_C_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_c.h b/src/core/hle/service/cam/cam_c.h new file mode 100644 index 00000000..6b296c00 --- /dev/null +++ b/src/core/hle/service/cam/cam_c.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_C_Interface : public Service::Interface { +public: + CAM_C_Interface(); + + std::string GetPortName() const override { + return "cam:c"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp new file mode 100644 index 00000000..c2760a10 --- /dev/null +++ b/src/core/hle/service/cam/cam_q.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_q.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_Q_Interface::CAM_Q_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h new file mode 100644 index 00000000..07cc1253 --- /dev/null +++ b/src/core/hle/service/cam/cam_q.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_Q_Interface : public Service::Interface { +public: + CAM_Q_Interface(); + + std::string GetPortName() const override { + return "cam:q"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp new file mode 100644 index 00000000..aefbf7df --- /dev/null +++ b/src/core/hle/service/cam/cam_s.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_s.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_S_Interface::CAM_S_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_s.h b/src/core/hle/service/cam/cam_s.h new file mode 100644 index 00000000..0a5d6fca --- /dev/null +++ b/src/core/hle/service/cam/cam_s.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_S_Interface : public Service::Interface { +public: + CAM_S_Interface(); + + std::string GetPortName() const override { + return "cam:s"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp new file mode 100644 index 00000000..1c6aca95 --- /dev/null +++ b/src/core/hle/service/cam/cam_u.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_u.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_U_Interface::CAM_U_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_u.h b/src/core/hle/service/cam/cam_u.h new file mode 100644 index 00000000..36926403 --- /dev/null +++ b/src/core/hle/service/cam/cam_u.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_U_Interface : public Service::Interface { +public: + CAM_U_Interface(); + + std::string GetPortName() const override { + return "cam:u"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp deleted file mode 100644 index fcfd8771..00000000 --- a/src/core/hle/service/cam_u.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/cam_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CAM_U - -namespace CAM_U { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/cam_u.h b/src/core/hle/service/cam_u.h deleted file mode 100644 index 878c20a8..00000000 --- a/src/core/hle/service/cam_u.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CAM_U - -namespace CAM_U { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "cam:u"; - } -}; - -} // namespace diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp new file mode 100644 index 00000000..db0e52b7 --- /dev/null +++ b/src/core/hle/service/cecd/cecd.cpp @@ -0,0 +1,31 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_s.h" +#include "core/hle/service/cecd/cecd_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace CECD { + +void Init() { + using namespace Kernel; + + AddService(new CECD_S_Interface); + AddService(new CECD_U_Interface); +} + +void Shutdown() { +} + +} // namespace CECD + +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h new file mode 100644 index 00000000..32fd2045 --- /dev/null +++ b/src/core/hle/service/cecd/cecd.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace CECD { + +/// Initialize CECD service(s) +void Init(); + +/// Shutdown CECD service(s) +void Shutdown(); + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp new file mode 100644 index 00000000..72d7e8d4 --- /dev/null +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_s.h" + +namespace Service { +namespace CECD { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CECD_S_Interface::CECD_S_Interface() { + //Register(FunctionTable); +} + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h index d880d039..df5c0184 100644 --- a/src/core/hle/service/cecd_s.h +++ b/src/core/hle/service/cecd/cecd_s.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_S +namespace Service { +namespace CECD { -namespace CECD_S { - -class Interface : public Service::Interface { +class CECD_S_Interface : public Interface { public: - Interface(); + CECD_S_Interface(); std::string GetPortName() const override { return "cecd:s"; } }; -} // namespace +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp new file mode 100644 index 00000000..0a23bafb --- /dev/null +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -0,0 +1,20 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_u.h" + +namespace Service { +namespace CECD { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CECD_U_Interface::CECD_U_Interface() { + //Register(FunctionTable); +} + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h index e6756413..394030ff 100644 --- a/src/core/hle/service/cecd_u.h +++ b/src/core/hle/service/cecd/cecd_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_U +namespace Service { +namespace CECD { -namespace CECD_U { - -class Interface : public Service::Interface { +class CECD_U_Interface : public Interface { public: - Interface(); + CECD_U_Interface(); std::string GetPortName() const override { return "cecd:u"; } }; -} // namespace +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd_s.cpp b/src/core/hle/service/cecd_s.cpp deleted file mode 100644 index b298f151..00000000 --- a/src/core/hle/service/cecd_s.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/cecd_s.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_S - -namespace CECD_S { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/cecd_u.cpp b/src/core/hle/service/cecd_u.cpp deleted file mode 100644 index 9125364b..00000000 --- a/src/core/hle/service/cecd_u.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/cecd_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_U - -namespace CECD_U { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index d4268288..62ad90fd 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -315,11 +315,11 @@ void Init() { AddService(new CFG_I_Interface); AddService(new CFG_S_Interface); AddService(new CFG_U_Interface); - + // Open the SystemSaveData archive 0x00010017 FileSys::Path archive_path(cfg_system_savedata_id); auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); - + // If the archive didn't exist, create the files inside if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { // Format the archive to create the directories diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp new file mode 100644 index 00000000..2911ab40 --- /dev/null +++ b/src/core/hle/service/frd/frd.cpp @@ -0,0 +1,29 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/service.h" +#include "core/hle/service/frd/frd.h" +#include "core/hle/service/frd/frd_a.h" +#include "core/hle/service/frd/frd_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace FRD { + +void Init() { + using namespace Kernel; + + AddService(new FRD_A_Interface); + AddService(new FRD_U_Interface); +} + +void Shutdown() { +} + +} // namespace FRD + +} // namespace Service diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h new file mode 100644 index 00000000..41f7a2f6 --- /dev/null +++ b/src/core/hle/service/frd/frd.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace FRD { + +/// Initialize FRD service(s) +void Init(); + +/// Shutdown FRD service(s) +void Shutdown(); + +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp new file mode 100644 index 00000000..1c438a33 --- /dev/null +++ b/src/core/hle/service/frd/frd_a.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/frd/frd.h" +#include "core/hle/service/frd/frd_a.h" + +namespace Service { +namespace FRD { + +// Empty arrays are illegal -- commented out until an entry is added. +// const Interface::FunctionInfo FunctionTable[] = { }; + +FRD_A_Interface::FRD_A_Interface() { + //Register(FunctionTable); +} + +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_a.h b/src/core/hle/service/frd/frd_a.h index f068c610..006d1cad 100644 --- a/src/core/hle/service/frd_a.h +++ b/src/core/hle/service/frd/frd_a.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_A +namespace Service { +namespace FRD { -namespace FRD_A { - -class Interface : public Service::Interface { +class FRD_A_Interface : public Service::Interface { public: - Interface(); + FRD_A_Interface(); std::string GetPortName() const override { return "frd:a"; } }; -} // namespace +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp index 6d2ff1e2..439c7282 100644 --- a/src/core/hle/service/frd_u.cpp +++ b/src/core/hle/service/frd/frd_u.cpp @@ -3,12 +3,11 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/frd_u.h" +#include "core/hle/service/frd/frd.h" +#include "core/hle/service/frd/frd_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_U - -namespace FRD_U { +namespace Service { +namespace FRD { const Interface::FunctionInfo FunctionTable[] = { {0x00050000, nullptr, "GetFriendKey"}, @@ -22,11 +21,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00320042, nullptr, "SetClientSdkVersion"} }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +FRD_U_Interface::FRD_U_Interface() { Register(FunctionTable); } -} // namespace +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd/frd_u.h index ab8897d5..07e43f15 100644 --- a/src/core/hle/service/frd_u.h +++ b/src/core/hle/service/frd/frd_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_U +namespace Service { +namespace FRD { -namespace FRD_U { - -class Interface : public Service::Interface { +class FRD_U_Interface : public Service::Interface { public: - Interface(); + FRD_U_Interface(); std::string GetPortName() const override { return "frd:u"; } }; -} // namespace +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_a.cpp b/src/core/hle/service/frd_a.cpp deleted file mode 100644 index 56997931..00000000 --- a/src/core/hle/service/frd_a.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/frd_a.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_A - -namespace FRD_A { - -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 6d4a9c7c..4e275cb1 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -254,7 +254,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); - // This should never even happen in the first place with 64-bit handles, + // This should never even happen in the first place with 64-bit handles, while (handle_map.count(next_handle) != 0) { ++next_handle; } @@ -406,7 +406,7 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { return archive_itr->second->Format(path); } -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) { +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); @@ -421,9 +421,25 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) { } std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); - std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); - if (!FileUtil::CreateFullPath(extsavedata_path)) + std::string game_path = FileSys::GetExtSaveDataPath(base_path, path); + // These two folders are always created with the ExtSaveData + std::string user_path = game_path + "user/"; + std::string boss_path = game_path + "boss/"; + if (!FileUtil::CreateFullPath(user_path)) + return ResultCode(-1); // TODO(Subv): Find the right error code + if (!FileUtil::CreateFullPath(boss_path)) + return ResultCode(-1); // TODO(Subv): Find the right error code + + u8* smdh_icon = Memory::GetPointer(icon_buffer); + if (!smdh_icon) return ResultCode(-1); // TODO(Subv): Find the right error code + + // Create the icon + FileUtil::IOFile icon_file(game_path + "icon", "wb+"); + if (!icon_file.IsGood()) + return ResultCode(-1); // TODO(Subv): Find the right error code + + icon_file.WriteBytes(smdh_icon, icon_size); return RESULT_SUCCESS; } @@ -441,6 +457,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { return ResultCode(-1); // TODO(Subv): Find the right error code } + // Delete all directories (/user, /boss) and the icon file. std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); if (!FileUtil::DeleteDirRecursively(extsavedata_path)) @@ -488,7 +505,7 @@ void ArchiveInit() { RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC); else LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); - + // Create the SaveData archive auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory); RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); @@ -503,7 +520,7 @@ void ArchiveInit() { if (sharedextsavedata_factory->Initialize()) RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData); else - LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", + LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", sharedextsavedata_factory->GetMountPoint().c_str()); // Create the SaveDataCheck archive, basically a small variation of the RomFS archive diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index faab0cb7..357b6b09 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -177,9 +177,11 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File * @param media_type The media type of the archive to create (NAND / SDMC) * @param high The high word of the extdata id to create * @param low The low word of the extdata id to create + * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData + * @param icon_size Size of the SMDH icon * @return ResultCode 0 on success or the corresponding code on error */ -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low); +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size); /** * Deletes the SharedExtSaveData archive for the specified extdata ID diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index b25c8941..0ad44e55 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -434,7 +434,7 @@ static void IsSdmcWriteable(Service::Interface* self) { } /** - * FS_User::FormatSaveData service function, + * FS_User::FormatSaveData service function, * formats the SaveData specified by the input path. * Inputs: * 0 : 0x084C0242 @@ -504,9 +504,9 @@ static void FormatThisUserSaveData(Service::Interface* self) { * 6 : Unknown * 7 : Unknown * 8 : Unknown - * 9 : Unknown - * 10: Unknown - * 11: Unknown + * 9 : Size of the SMDH icon + * 10: (SMDH Size << 4) | 0x0000000A + * 11: Pointer to the SMDH icon for the new ExtSaveData * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ @@ -516,14 +516,16 @@ static void CreateExtSaveData(Service::Interface* self) { MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF); u32 save_low = cmd_buff[2]; u32 save_high = cmd_buff[3]; + u32 icon_size = cmd_buff[9]; + VAddr icon_buffer = cmd_buff[11]; LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " - "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low, - cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9], - cmd_buff[10], cmd_buff[11]); + "icon_size=%08X icon_descriptor=%08X icon_buffer=%08X", save_high, save_low, + cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size, + cmd_buff[10], icon_buffer); - cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; + cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw; } /** @@ -544,7 +546,7 @@ static void DeleteExtSaveData(Service::Interface* self) { u32 save_high = cmd_buff[3]; u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is - LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", + LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", save_low, save_high, cmd_buff[1] & 0xFF, unknown); cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw; diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index c56475ae..4b0b4229 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -167,7 +167,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; - + u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); @@ -208,21 +208,21 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); if (info.active_fb == 0) { - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, &phys_address_left); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, &phys_address_right); } else { - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, &phys_address_left); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, &phys_address_right); } - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, &info.stride); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, &info.format); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, &info.shown_fb); } @@ -374,7 +374,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { { auto& params = command.set_command_list_last; - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)), + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)), Memory::VirtualToPhysicalAddress(params.address) >> 3); WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size); @@ -470,7 +470,7 @@ static void SetLcdForceBlack(Service::Interface* self) { LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD - + cmd_buff[1] = RESULT_SUCCESS.raw; } @@ -496,6 +496,52 @@ static void TriggerCmdReqQueue(Service::Interface* self) { cmd_buff[1] = 0; // No error } +/** + * GSP_GPU::ImportDisplayCaptureInfo service function + * + * Returns information about the current framebuffer state + * + * Inputs: + * 0: Header 0x00180000 + * Outputs: + * 1: Result code + * 2: Left framebuffer virtual address for the main screen + * 3: Right framebuffer virtual address for the main screen + * 4: Main screen framebuffer format + * 5: Main screen framebuffer width + * 6: Left framebuffer virtual address for the bottom screen + * 7: Right framebuffer virtual address for the bottom screen + * 8: Bottom screen framebuffer format + * 9: Bottom screen framebuffer width + */ +static void ImportDisplayCaptureInfo(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0, + // because we only support a single running application at a time. + // This should always return the framebuffer data that is currently displayed on the screen. + + u32 thread_id = 0; + + FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0); + FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1); + + cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left; + cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right; + cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format; + cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride; + + cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left; + cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right; + cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format; + cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride; + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_GSP, "called"); +} + + const Interface::FunctionInfo FunctionTable[] = { {0x00010082, WriteHWRegs, "WriteHWRegs"}, {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"}, @@ -520,7 +566,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00150002, nullptr, "TryAcquireRight"}, {0x00160042, nullptr, "AcquireRight"}, {0x00170000, nullptr, "ReleaseRight"}, - {0x00180000, nullptr, "ImportDisplayCaptureInfo"}, + {0x00180000, ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"}, {0x00190000, nullptr, "SaveVramSysArea"}, {0x001A0000, nullptr, "RestoreVramSysArea"}, {0x001B0000, nullptr, "ResetGpuCore"}, diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 2d2133b2..c7c1bb5a 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -58,7 +58,7 @@ void Update() { mem->pad.current_state.hex = state.hex; mem->pad.index = next_pad_index; - ++next_touch_index %= mem->pad.entries.size(); + next_touch_index = (next_touch_index + 1) % mem->pad.entries.size(); // Get the previous Pad state u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size(); @@ -88,7 +88,7 @@ void Update() { } mem->touch.index = next_touch_index; - ++next_touch_index %= mem->touch.entries.size(); + next_touch_index = (next_touch_index + 1) % mem->touch.entries.size(); // Get the current touch entry TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index]; @@ -106,7 +106,7 @@ void Update() { mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); } - + // Signal both handles when there's an update to Pad or touch event_pad_or_touch_1->Signal(); event_pad_or_touch_2->Signal(); diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index 02db12ef..532931ae 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -25,6 +25,6 @@ const Interface::FunctionInfo FunctionTable[] = { HID_SPVR_Interface::HID_SPVR_Interface() { Register(FunctionTable); } - + } // namespace HID } // namespace Service diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h index 0eeec2c2..baf7fed7 100644 --- a/src/core/hle/service/hid/hid_user.h +++ b/src/core/hle/service/hid/hid_user.h @@ -11,7 +11,7 @@ namespace Service { namespace HID { - + /** * HID service interface. */ diff --git a/src/core/hle/service/news/news.cpp b/src/core/hle/service/news/news.cpp new file mode 100644 index 00000000..63cbd385 --- /dev/null +++ b/src/core/hle/service/news/news.cpp @@ -0,0 +1,31 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/news/news_s.h" +#include "core/hle/service/news/news_u.h" + +#include "core/hle/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" + +namespace Service { +namespace NEWS { + +void Init() { + using namespace Kernel; + + AddService(new NEWS_S_Interface); + AddService(new NEWS_U_Interface); +} + +void Shutdown() { +} + +} // namespace NEWS + +} // namespace Service diff --git a/src/core/hle/service/news/news.h b/src/core/hle/service/news/news.h new file mode 100644 index 00000000..b31ade25 --- /dev/null +++ b/src/core/hle/service/news/news.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace NEWS { + +/// Initialize NEWS service(s) +void Init(); + +/// Shutdown NEWS service(s) +void Shutdown(); + +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp new file mode 100644 index 00000000..2f8c37d9 --- /dev/null +++ b/src/core/hle/service/news/news_s.cpp @@ -0,0 +1,21 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/news/news_s.h" + +namespace Service { +namespace NEWS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C6, nullptr, "AddNotification"}, +}; + +NEWS_S_Interface::NEWS_S_Interface() { + Register(FunctionTable); +} + +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news_s.h b/src/core/hle/service/news/news_s.h index f8b4636d..f58b969a 100644 --- a/src/core/hle/service/news_s.h +++ b/src/core/hle/service/news/news_s.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_S +namespace Service { +namespace NEWS { -namespace NEWS_S { - -class Interface : public Service::Interface { +class NEWS_S_Interface : public Service::Interface { public: - Interface(); + NEWS_S_Interface(); std::string GetPortName() const override { return "news:s"; } }; -} // namespace +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news/news_u.cpp b/src/core/hle/service/news/news_u.cpp new file mode 100644 index 00000000..81f45a24 --- /dev/null +++ b/src/core/hle/service/news/news_u.cpp @@ -0,0 +1,21 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/news/news_u.h" + +namespace Service { +namespace NEWS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C6, nullptr, "AddNotification"}, +}; + +NEWS_U_Interface::NEWS_U_Interface() { + Register(FunctionTable); +} + +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news_u.h b/src/core/hle/service/news/news_u.h index 0473cd19..2720053d 100644 --- a/src/core/hle/service/news_u.h +++ b/src/core/hle/service/news/news_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_U +namespace Service { +namespace NEWS { -namespace NEWS_U { - -class Interface : public Service::Interface { +class NEWS_U_Interface : public Service::Interface { public: - Interface(); + NEWS_U_Interface(); std::string GetPortName() const override { return "news:u"; } }; -} // namespace +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news_s.cpp b/src/core/hle/service/news_s.cpp deleted file mode 100644 index 302d588c..00000000 --- a/src/core/hle/service/news_s.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/news_s.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_S - -namespace NEWS_S { - -const Interface::FunctionInfo FunctionTable[] = { - {0x000100C6, nullptr, "AddNotification"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/news_u.cpp b/src/core/hle/service/news_u.cpp deleted file mode 100644 index 7d835aa3..00000000 --- a/src/core/hle/service/news_u.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/news_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_U - -namespace NEWS_U { - -const Interface::FunctionInfo FunctionTable[] = { - {0x000100C8, nullptr, "AddNotification"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp new file mode 100644 index 00000000..73b0ee52 --- /dev/null +++ b/src/core/hle/service/nim/nim.cpp @@ -0,0 +1,42 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_aoc.h" +#include "core/hle/service/nim/nim_s.h" +#include "core/hle/service/nim/nim_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace NIM { + +void CheckSysUpdateAvailable(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; // No update available + + LOG_WARNING(Service_NWM, "(STUBBED) called"); +} + +void Init() { + using namespace Kernel; + + AddService(new NIM_AOC_Interface); + AddService(new NIM_S_Interface); + AddService(new NIM_U_Interface); +} + +void Shutdown() { +} + +} // namespace NIM + +} // namespace Service diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h new file mode 100644 index 00000000..f7635c74 --- /dev/null +++ b/src/core/hle/service/nim/nim.h @@ -0,0 +1,30 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +/** + * NIM::CheckSysUpdateAvailable service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : flag, 0 = no system update available, 1 = system update available. + */ +void CheckSysUpdateAvailable(Service::Interface* self); + +/// Initialize NIM service(s) +void Init(); + +/// Shutdown NIM service(s) +void Shutdown(); + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim_aoc.cpp b/src/core/hle/service/nim/nim_aoc.cpp index 7a6aea91..e6b1b614 100644 --- a/src/core/hle/service/nim_aoc.cpp +++ b/src/core/hle/service/nim/nim_aoc.cpp @@ -3,12 +3,11 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/nim_aoc.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_aoc.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_AOC - -namespace NIM_AOC { +namespace Service { +namespace NIM { const Interface::FunctionInfo FunctionTable[] = { {0x00030042, nullptr, "SetApplicationId"}, @@ -20,11 +19,10 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00240282, nullptr, "CalculateContentsRequiredSize"}, {0x00250000, nullptr, "RefreshServerTime"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class -Interface::Interface() { +NIM_AOC_Interface::NIM_AOC_Interface() { Register(FunctionTable); } -} // namespace +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim/nim_aoc.h b/src/core/hle/service/nim/nim_aoc.h new file mode 100644 index 00000000..aace45b5 --- /dev/null +++ b/src/core/hle/service/nim/nim_aoc.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +class NIM_AOC_Interface : public Service::Interface { +public: + NIM_AOC_Interface(); + + std::string GetPortName() const override { + return "nim:aoc"; + } +}; + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp new file mode 100644 index 00000000..5d8bc059 --- /dev/null +++ b/src/core/hle/service/nim/nim_s.cpp @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_s.h" + +namespace Service { +namespace NIM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"}, +}; + +NIM_S_Interface::NIM_S_Interface() { + Register(FunctionTable); +} + +} // namespace NIM +} // namespace Service + diff --git a/src/core/hle/service/nim/nim_s.h b/src/core/hle/service/nim/nim_s.h new file mode 100644 index 00000000..f4bf73d2 --- /dev/null +++ b/src/core/hle/service/nim/nim_s.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +class NIM_S_Interface : public Service::Interface { +public: + NIM_S_Interface(); + + std::string GetPortName() const override { + return "nim:s"; + } +}; + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp new file mode 100644 index 00000000..066570a8 --- /dev/null +++ b/src/core/hle/service/nim/nim_u.cpp @@ -0,0 +1,27 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_u.h" + +namespace Service { +namespace NIM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "StartSysUpdate"}, + {0x00020000, nullptr, "GetUpdateDownloadProgress"}, + {0x00040000, nullptr, "FinishTitlesInstall"}, + {0x00050000, nullptr, "CheckForSysUpdateEvent"}, + {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, + {0x000A0000, nullptr, "GetState"}, +}; + +NIM_U_Interface::NIM_U_Interface() { + Register(FunctionTable); +} + +} // namespace NIM +} // namespace Service + diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h new file mode 100644 index 00000000..bc89dc0f --- /dev/null +++ b/src/core/hle/service/nim/nim_u.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +class NIM_U_Interface : public Service::Interface { +public: + NIM_U_Interface(); + + std::string GetPortName() const override { + return "nim:u"; + } +}; + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim_aoc.h b/src/core/hle/service/nim_aoc.h deleted file mode 100644 index aeb71eed..00000000 --- a/src/core/hle/service/nim_aoc.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_AOC - -namespace NIM_AOC { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "nim:aoc"; - } -}; - -} // namespace diff --git a/src/core/hle/service/nim_u.cpp b/src/core/hle/service/nim_u.cpp deleted file mode 100644 index 5f13bd98..00000000 --- a/src/core/hle/service/nim_u.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" - -#include "core/hle/hle.h" -#include "core/hle/service/nim_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_U - -namespace NIM_U { - -/** - * NIM_U::CheckSysUpdateAvailable service function - * Inputs: - * 1 : None - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : flag, 0 = no system update available, 1 = system update available. - */ -static void CheckSysUpdateAvailable(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; // No update available - - LOG_WARNING(Service_NWM, "(STUBBED) called"); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010000, nullptr, "StartSysUpdate"}, - {0x00020000, nullptr, "GetUpdateDownloadProgress"}, - {0x00040000, nullptr, "FinishTitlesInstall"}, - {0x00050000, nullptr, "CheckForSysUpdateEvent"}, - {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, - {0x000A0000, nullptr, "GetState"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/nim_u.h b/src/core/hle/service/nim_u.h deleted file mode 100644 index 57a1f6ac..00000000 --- a/src/core/hle/service/nim_u.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_U - -namespace NIM_U { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "nim:u"; - } -}; - -} // namespace diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index 493e6a11..b690003c 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h @@ -20,15 +20,15 @@ enum class ChargeLevels : u32 { CompletelyFull = 5, }; -/** +/** * Represents the gamecoin file structure in the SharedExtData archive * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) */ struct GameCoin { u32 magic; ///< Magic number: 0x4F00 - u16 total_coins; ///< Total Play Coins + u16 total_coins; ///< Total Play Coins u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. - u32 step_count; ///< Total step count at the time a new Play Coin was obtained. + u32 step_count; ///< Total step count at the time a new Play Coin was obtained. u32 last_step_count; ///< Step count for the day the last Play Coin was obtained u16 year; u8 month; diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp index 48e68a3d..7bb99019 100644 --- a/src/core/hle/service/ptm/ptm_play.cpp +++ b/src/core/hle/service/ptm/ptm_play.cpp @@ -18,6 +18,6 @@ const Interface::FunctionInfo FunctionTable[] = { PTM_Play_Interface::PTM_Play_Interface() { Register(FunctionTable); } - + } // namespace PTM } // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 64185c62..d681cc3d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -8,29 +8,15 @@ #include "core/hle/service/service.h" #include "core/hle/service/ac_u.h" #include "core/hle/service/act_u.h" -#include "core/hle/service/am_app.h" -#include "core/hle/service/am_net.h" -#include "core/hle/service/am_sys.h" -#include "core/hle/service/boss_p.h" -#include "core/hle/service/boss_u.h" -#include "core/hle/service/cam_u.h" -#include "core/hle/service/cecd_u.h" -#include "core/hle/service/cecd_s.h" #include "core/hle/service/csnd_snd.h" #include "core/hle/service/dsp_dsp.h" #include "core/hle/service/err_f.h" -#include "core/hle/service/frd_a.h" -#include "core/hle/service/frd_u.h" #include "core/hle/service/gsp_gpu.h" #include "core/hle/service/gsp_lcd.h" #include "core/hle/service/http_c.h" #include "core/hle/service/ldr_ro.h" #include "core/hle/service/mic_u.h" #include "core/hle/service/ndm_u.h" -#include "core/hle/service/news_s.h" -#include "core/hle/service/news_u.h" -#include "core/hle/service/nim_aoc.h" -#include "core/hle/service/nim_u.h" #include "core/hle/service/ns_s.h" #include "core/hle/service/nwm_uds.h" #include "core/hle/service/pm_app.h" @@ -39,11 +25,18 @@ #include "core/hle/service/ssl_c.h" #include "core/hle/service/y2r_u.h" +#include "core/hle/service/am/am.h" #include "core/hle/service/apt/apt.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/frd/frd.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/ir/ir.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/nim/nim.h" #include "core/hle/service/ptm/ptm.h" namespace Service { @@ -52,7 +45,7 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_por std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; /** - * Creates a function string for logging, complete with the name (or header code, depending + * Creates a function string for logging, complete with the name (or header code, depending * on what's passed in) the port name, and all the cmd_buff arguments. */ static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { @@ -111,36 +104,29 @@ void Init() { AddNamedPort(new ERR_F::Interface); Service::FS::ArchiveInit(); - Service::CFG::Init(); + Service::AM::Init(); Service::APT::Init(); - Service::PTM::Init(); + Service::BOSS::Init(); + Service::CAM::Init(); + Service::CECD::Init(); + Service::CFG::Init(); + Service::FRD::Init(); Service::HID::Init(); Service::IR::Init(); + Service::NEWS::Init(); + Service::NIM::Init(); + Service::PTM::Init(); AddService(new AC_U::Interface); AddService(new ACT_U::Interface); - AddService(new AM_APP::Interface); - AddService(new AM_NET::Interface); - AddService(new AM_SYS::Interface); - AddService(new BOSS_P::Interface); - AddService(new BOSS_U::Interface); - AddService(new CAM_U::Interface); - AddService(new CECD_S::Interface); - AddService(new CECD_U::Interface); AddService(new CSND_SND::Interface); AddService(new DSP_DSP::Interface); - AddService(new FRD_A::Interface); - AddService(new FRD_U::Interface); AddService(new GSP_GPU::Interface); AddService(new GSP_LCD::Interface); AddService(new HTTP_C::Interface); AddService(new LDR_RO::Interface); AddService(new MIC_U::Interface); AddService(new NDM_U::Interface); - AddService(new NEWS_S::Interface); - AddService(new NEWS_U::Interface); - AddService(new NIM_AOC::Interface); - AddService(new NIM_U::Interface); AddService(new NS_S::Interface); AddService(new NWM_UDS::Interface); AddService(new PM_APP::Interface); @@ -153,11 +139,19 @@ void Init() { /// Shutdown ServiceManager void Shutdown() { + + Service::PTM::Shutdown(); + Service::NIM::Shutdown(); + Service::NEWS::Shutdown(); Service::IR::Shutdown(); Service::HID::Shutdown(); - Service::PTM::Shutdown(); - Service::APT::Shutdown(); + Service::FRD::Shutdown(); Service::CFG::Shutdown(); + Service::CECD::Shutdown(); + Service::CAM::Shutdown(); + Service::BOSS::Shutdown(); + Service::APT::Shutdown(); + Service::AM::Shutdown(); Service::FS::ArchiveShutdown(); g_srv_services.clear(); diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 39b8d65f..1e0f5df9 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -139,7 +139,7 @@ static int TranslateError(int error) { auto found = error_map.find(error); if (found != error_map.end()) return -found->second; - + return error; } @@ -346,7 +346,7 @@ static void Bind(Service::Interface* self) { sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr); int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); - + int result = 0; if (res != 0) result = TranslateError(GET_ERRNO); @@ -360,14 +360,14 @@ static void Fcntl(Service::Interface* self) { u32 socket_handle = cmd_buffer[1]; u32 ctr_cmd = cmd_buffer[2]; u32 ctr_arg = cmd_buffer[3]; - + int result = 0; u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX) SCOPE_EXIT({ cmd_buffer[1] = result; cmd_buffer[2] = posix_ret; }); - + if (ctr_cmd == 3) { // F_GETFL #if EMU_PLATFORM == PLATFORM_WINDOWS posix_ret = 0; @@ -404,11 +404,11 @@ static void Fcntl(Service::Interface* self) { posix_ret = -1; return; } - + flags &= ~O_NONBLOCK; if (ctr_arg & 4) // O_NONBLOCK flags |= O_NONBLOCK; - + int ret = ::fcntl(socket_handle, F_SETFL, flags); if (ret == SOCKET_ERROR_VALUE) { result = TranslateError(GET_ERRNO); @@ -439,8 +439,8 @@ static void Listen(Service::Interface* self) { } static void Accept(Service::Interface* self) { - // TODO(Subv): Calling this function on a blocking socket will block the emu thread, - // preventing graceful shutdown when closing the emulator, this can be fixed by always + // TODO(Subv): Calling this function on a blocking socket will block the emu thread, + // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; @@ -448,7 +448,7 @@ static void Accept(Service::Interface* self) { sockaddr addr; socklen_t addr_len = sizeof(addr); u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len)); - + if ((s32)ret != SOCKET_ERROR_VALUE) open_sockets[ret] = { ret, true }; @@ -525,8 +525,8 @@ static void SendTo(Service::Interface* self) { } static void RecvFrom(Service::Interface* self) { - // TODO(Subv): Calling this function on a blocking socket will block the emu thread, - // preventing graceful shutdown when closing the emulator, this can be fixed by always + // TODO(Subv): Calling this function on a blocking socket will block the emu thread, + // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; @@ -568,7 +568,7 @@ static void Poll(Service::Interface* self) { pollfd* platform_pollfd = new pollfd[nfds]; for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]); - + int ret = ::poll(platform_pollfd, nfds, timeout); // Now update the output pollfd structure @@ -630,7 +630,7 @@ static void GetPeerName(Service::Interface* self) { socklen_t len = cmd_buffer[2]; CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); - + sockaddr dest_addr; socklen_t dest_addr_len = sizeof(dest_addr); int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len); @@ -651,8 +651,8 @@ static void GetPeerName(Service::Interface* self) { } static void Connect(Service::Interface* self) { - // TODO(Subv): Calling this function on a blocking socket will block the emu thread, - // preventing graceful shutdown when closing the emulator, this can be fixed by always + // TODO(Subv): Calling this function on a blocking socket will block the emu thread, + // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 347d241f..6cde4fc8 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -40,9 +40,6 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E -/// An invalid result code that is meant to be overwritten when a thread resumes from waiting -const ResultCode RESULT_INVALID(0xDEADC0DE); - enum ControlMemoryOperation { MEMORY_OPERATION_HEAP = 0x00000003, MEMORY_OPERATION_GSP_HEAP = 0x00010003, @@ -143,6 +140,10 @@ static ResultCode CloseHandle(Handle handle) { /// Wait for a handle to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { auto object = Kernel::g_handle_table.GetWaitObject(handle); + Kernel::Thread* thread = Kernel::GetCurrentThread(); + + thread->waitsynch_waited = false; + if (object == nullptr) return ERR_INVALID_HANDLE; @@ -154,14 +155,14 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { // Check for next thread to schedule if (object->ShouldWait()) { - object->AddWaitingThread(Kernel::GetCurrentThread()); + object->AddWaitingThread(thread); Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); // Create an event to wake the thread up after the specified nanosecond delay has passed - Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); + thread->WakeAfterDelay(nano_seconds); // NOTE: output of this SVC will be set later depending on how the thread resumes - return RESULT_INVALID; + return HLE::RESULT_INVALID; } object->Acquire(); @@ -173,6 +174,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { bool wait_thread = !wait_all; int handle_index = 0; + Kernel::Thread* thread = Kernel::GetCurrentThread(); + bool was_waiting = thread->waitsynch_waited; + thread->waitsynch_waited = false; // Check if 'handles' is invalid if (handles == nullptr) @@ -190,6 +194,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou // necessary if (handle_count != 0) { bool selected = false; // True once an object has been selected + + Kernel::SharedPtr<Kernel::WaitObject> wait_object; + for (int i = 0; i < handle_count; ++i) { auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); if (object == nullptr) @@ -204,10 +211,11 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou wait_thread = true; } else { // Do not wait on this object, check if this object should be selected... - if (!wait_all && !selected) { + if (!wait_all && (!selected || (wait_object == object && was_waiting))) { // Do not wait the thread wait_thread = false; handle_index = i; + wait_object = object; selected = true; } } @@ -228,7 +236,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou // Actually wait the current thread on each object if we decided to wait... std::vector<SharedPtr<Kernel::WaitObject>> wait_objects; wait_objects.reserve(handle_count); - + for (int i = 0; i < handle_count; ++i) { auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); object->AddWaitingThread(Kernel::GetCurrentThread()); @@ -241,7 +249,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); // NOTE: output of this SVC will be set later depending on how the thread resumes - return RESULT_INVALID; + return HLE::RESULT_INVALID; } // Acquire objects if we did not wait... @@ -261,7 +269,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does // not seem to set it to any meaningful value. - *out = wait_all ? 0 : handle_index; + *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0; return RESULT_SUCCESS; } @@ -475,7 +483,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { return ERR_INVALID_HANDLE; const SharedPtr<Kernel::Process> process = thread->owner_process; - + ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); *process_id = process->process_id; @@ -654,6 +662,8 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 using Kernel::MemoryPermission; SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size, (MemoryPermission)my_permission, (MemoryPermission)other_permission); + // Map the SharedMemory to the specified address + shared_memory->base_address = addr; CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index ddc5d647..7471def5 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/color.h" #include "common/common_types.h" #include "core/arm/arm_interface.h" @@ -22,7 +23,6 @@ #include "video_core/command_processor.h" #include "video_core/utils.h" #include "video_core/video_core.h" -#include "video_core/color.h" namespace GPU { @@ -30,8 +30,8 @@ Regs g_regs; /// True if the current frame was skipped bool g_skip_frame; -/// 268MHz / gpu_refresh_rate frames per second -static u64 frame_ticks; +/// 268MHz CPU clocks / 60Hz frames per second +const u64 frame_ticks = 268123480ull / 60; /// Event id for CoreTiming static int vblank_event; /// Total number of frames drawn @@ -140,7 +140,7 @@ inline void Write(u32 addr, const T data) { // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions // TODO(Subv): Verify if raw copies perform scaling memcpy(dst_pointer, src_pointer, output_size); - + LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy", output_size, config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(), @@ -159,14 +159,14 @@ inline void Write(u32 addr, const T data) { for (u32 x = 0; x < output_width; ++x) { Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; - // Calculate the [x,y] position of the input image + // Calculate the [x,y] position of the input image // based on the current output position and the scale u32 input_x = x * horizontal_scale; u32 input_y = y * vertical_scale; if (config.flip_vertically) { - // Flip the y value of the output data, - // we do this after calculating the [x,y] position of the input image + // Flip the y value of the output data, + // we do this after calculating the [x,y] position of the input image // to account for the scaling options. y = output_height - y - 1; } @@ -302,7 +302,7 @@ static void VBlankCallback(u64 userdata, int cycles_late) { // - If frameskip == 0 (disabled), always swap buffers // - If frameskip == 1, swap buffers every other frame (starting from the first frame) // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame) - if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || + if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || Settings::values.frame_skip == 0) { VideoCore::g_renderer->SwapBuffers(); } @@ -357,7 +357,6 @@ void Init() { framebuffer_sub.color_format = Regs::PixelFormat::RGB8; framebuffer_sub.active_fb = 0; - frame_ticks = 268123480 / Settings::values.gpu_refresh_rate; last_skip_frame = false; g_skip_frame = false; frame_count = 0; diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index f4906cc7..c7006a49 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -18,7 +18,7 @@ inline void Read(T &var, const u32 addr) { GPU::Read(var, addr); break; case VADDR_LCD: - LCD::Write(var, addr); + LCD::Read(var, addr); break; default: LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp index 09134c95..963c8d98 100644 --- a/src/core/hw/lcd.cpp +++ b/src/core/hw/lcd.cpp @@ -66,5 +66,5 @@ void Init() { void Shutdown() { LOG_DEBUG(HW_LCD, "shutdown OK"); } - + } // namespace diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h index fb14c3b2..8631eb20 100644 --- a/src/core/hw/lcd.h +++ b/src/core/hw/lcd.h @@ -85,5 +85,5 @@ void Init(); /// Shutdown hardware void Shutdown(); - + } // namespace diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index ad5e929c..14aeebeb 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -234,7 +234,7 @@ ResultStatus AppLoader_THREEDSX::Load() { Kernel::g_current_process = Kernel::Process::Create(filename, 0); Kernel::g_current_process->svc_access_mask.set(); Kernel::g_current_process->address_mappings = default_address_mappings; - + // Attach the default resource limit (APPLICATION) to the process Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index 5ecec956..bf814b94 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp @@ -8,6 +8,10 @@ #include "common/logging/log.h" #include "core/hle/config_mem.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/vm_manager.h" +#include "core/hle/result.h" #include "core/hle/shared_page.h" #include "core/mem_map.h" #include "core/memory.h" @@ -17,31 +21,23 @@ namespace Memory { -u8* g_exefs_code; ///< ExeFS:/.code is loaded here -u8* g_heap; ///< Application heap (main memory) -u8* g_shared_mem; ///< Shared memory -u8* g_heap_linear; ///< Linear heap -u8* g_vram; ///< Video memory (VRAM) pointer -u8* g_dsp_mem; ///< DSP memory -u8* g_tls_mem; ///< TLS memory - namespace { struct MemoryArea { - u8** ptr; u32 base; u32 size; + const char* name; }; // We don't declare the IO regions in here since its handled by other means. static MemoryArea memory_areas[] = { - {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE}, - {&g_heap, HEAP_VADDR, HEAP_SIZE }, - {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE }, - {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE }, - {&g_vram, VRAM_VADDR, VRAM_SIZE }, - {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE }, - {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE }, + {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here + {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory) + {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory + {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory) + {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM) + {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory + {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory }; /// Represents a block of memory mapped by ControlMemory/MapMemoryBlock @@ -135,27 +131,34 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) { return addr | 0x80000000; } +// TODO(yuriks): Move this into Process +static Kernel::VMManager address_space; + void Init() { + using namespace Kernel; + InitMemoryMap(); for (MemoryArea& area : memory_areas) { - *area.ptr = new u8[area.size]; - MapMemoryRegion(area.base, area.size, *area.ptr); + auto block = std::make_shared<std::vector<u8>>(area.size); + address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap(); } - MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem); - MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page); - LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap); + 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(); + address_space.Reprotect(shared_page_vma, VMAPermission::Read); + + LOG_DEBUG(HW_Memory, "initialized OK"); } void Shutdown() { heap_map.clear(); heap_linear_map.clear(); - - for (MemoryArea& area : memory_areas) { - delete[] *area.ptr; - *area.ptr = nullptr; - } + address_space.Reset(); LOG_DEBUG(HW_Memory, "shutdown OK"); } diff --git a/src/core/mem_map.h b/src/core/mem_map.h index 945815cd..ba50914a 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -8,14 +8,6 @@ namespace Memory { -extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here -extern u8* g_heap; ///< Application heap (main memory) -extern u8* g_shared_mem; ///< Shared memory -extern u8* g_heap_linear; ///< Linear heap (main memory) -extern u8* g_vram; ///< Video memory (VRAM) -extern u8* g_dsp_mem; ///< DSP memory -extern u8* g_tls_mem; ///< TLS memory - void Init(); void Shutdown(); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 5d8069ac..28844a91 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -14,12 +14,10 @@ #include "core/hw/hw.h" #include "core/mem_map.h" #include "core/memory.h" +#include "core/memory_setup.h" namespace Memory { -const u32 PAGE_MASK = PAGE_SIZE - 1; -const int PAGE_BITS = 12; - enum class PageType { /// Page is unmapped and should cause an access error. Unmapped, @@ -64,7 +62,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { while (base != end) { ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); - if (current_page_table->attributes[base] != PageType::Unmapped) { + if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) { LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE); } current_page_table->attributes[base] = type; @@ -92,6 +90,12 @@ void MapIoRegion(VAddr base, u32 size) { MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); } +void UnmapRegion(VAddr base, u32 size) { + ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); + ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); + MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); +} + template <typename T> T Read(const VAddr vaddr) { const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; diff --git a/src/core/memory.h b/src/core/memory.h index 2d225801..0b8ff9ec 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -97,7 +97,7 @@ enum : VAddr { SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, // TODO(yuriks): The size of this area is dynamic, the kernel grows - // it as more and more threads are created. For now we'll just use a + // it as more and more threads are created. For now we'll just use a // hardcoded value. /// Area where TLS (Thread-Local Storage) buffers are allocated. TLS_AREA_VADDR = 0x1FF82000, diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h index 46263495..361bfc81 100644 --- a/src/core/memory_setup.h +++ b/src/core/memory_setup.h @@ -6,8 +6,13 @@ #include "common/common_types.h" +#include "core/memory.h" + namespace Memory { +const u32 PAGE_MASK = PAGE_SIZE - 1; +const int PAGE_BITS = 12; + void InitMemoryMap(); /** @@ -26,4 +31,6 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target); */ void MapIoRegion(VAddr base, u32 size); +void UnmapRegion(VAddr base, u32 size); + } diff --git a/src/core/settings.h b/src/core/settings.h index 54c1023b..5a70d157 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -35,7 +35,6 @@ struct Values { int pad_cright_key; // Core - int gpu_refresh_rate; int frame_skip; // Data Storage |