exo: add smcAmsGetEmummcConfig
This commit is contained in:
@@ -13,8 +13,8 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "synchronization.h"
|
||||
#include "memory_map.h"
|
||||
#include "mmu.h"
|
||||
#include "userpage.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
static atomic_flag g_ams_userpage_mapped = ATOMIC_FLAG_INIT;
|
||||
static atomic_flag g_ams_iram_page_mapped = ATOMIC_FLAG_INIT;
|
||||
@@ -94,42 +96,42 @@ uint32_t ams_iram_copy(smc_args_t *args) {
|
||||
/* args->X[2] = IRAM address, must be 4-byte aligned. */
|
||||
/* args->X[3] = size (must be <= 0x1000 and 4-byte aligned). */
|
||||
/* args->X[4] = 0 for read, 1 for write. */
|
||||
|
||||
|
||||
const uintptr_t dram_address = (uintptr_t)args->X[1];
|
||||
const uintptr_t iram_address = (uintptr_t)args->X[2];
|
||||
const uintptr_t dram_page_offset = (dram_address & 0xFFFULL);
|
||||
const uintptr_t iram_page_offset = (iram_address & 0xFFFULL);
|
||||
const size_t size = args->X[3];
|
||||
const uint32_t option = (uint32_t)args->X[4];
|
||||
|
||||
|
||||
/* Validate addresses. */
|
||||
if (!ams_is_user_addr_valid(dram_address) || !ams_is_iram_addr_valid(iram_address)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Validate size. */
|
||||
if (size > 0x1000 || (size + dram_page_offset) > 0x1000 || (size + iram_page_offset) > 0x1000) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Validate alignment. */
|
||||
if (size % sizeof(uint32_t) || dram_page_offset % sizeof(uint32_t) || iram_page_offset % sizeof(uint32_t)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Validate argument. */
|
||||
if (option != 0 && option != 1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Map pages. */
|
||||
ams_map_userpage(dram_address);
|
||||
ams_map_irampage(iram_address);
|
||||
|
||||
|
||||
/* Set source/destination for copy. */
|
||||
volatile uint32_t *dram_ptr = (volatile uint32_t *)(AMS_USER_PAGE_SECURE_MONITOR_ADDR + dram_page_offset);
|
||||
volatile uint32_t *iram_ptr = (volatile uint32_t *)(AMS_IRAM_PAGE_SECURE_MONITOR_ADDR + iram_page_offset);
|
||||
|
||||
|
||||
volatile uint32_t *dst;
|
||||
volatile uint32_t *src;
|
||||
const size_t num_dwords = size / sizeof(uint32_t);
|
||||
@@ -140,19 +142,19 @@ uint32_t ams_iram_copy(smc_args_t *args) {
|
||||
dst = iram_ptr;
|
||||
src = dram_ptr;
|
||||
}
|
||||
|
||||
|
||||
/* Actually copy data. */
|
||||
for (size_t i = 0; i < num_dwords; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
|
||||
/* Flush! */
|
||||
flush_dcache_range((void *)dst, (void *)(dst + num_dwords));
|
||||
|
||||
flush_dcache_range((void *)dst, (void *)(dst + num_dwords));
|
||||
|
||||
/* Unmap pages. */
|
||||
ams_unmap_irampage();
|
||||
ams_unmap_userpage();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -222,3 +224,50 @@ uint32_t ams_write_address(smc_args_t *args) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t ams_get_emummc_config(smc_args_t *args) {
|
||||
/* This retrieves configuration for the current emummc context. */
|
||||
/* args->X[1] = MMC id, must be size-bytes aligned and readable by EL0. */
|
||||
/* args->X[2] = Pointer to output (for path for filebased), must be at least 0x80 bytes. */
|
||||
upage_ref_t page_ref;
|
||||
const uint32_t mmc_id = (uint32_t)args->X[1];
|
||||
void *user_address = (void *)args->X[2];
|
||||
const exo_emummc_config_t *emummc_cfg = exosphere_get_emummc_config();
|
||||
|
||||
if (mmc_id != EMUMMC_MMC_NAND) {
|
||||
/* Emummc config for non-NAND storage is not yet implemented. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_NONE) {
|
||||
/* Just copy base config. */
|
||||
memset(args, 0, sizeof(*args));
|
||||
memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg));
|
||||
_Static_assert(sizeof(emummc_cfg->base_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand base config too big!");
|
||||
return 0;
|
||||
} else if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_PARTITION) {
|
||||
/* Copy base config and partition config. */
|
||||
memset(args, 0, sizeof(*args));
|
||||
memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg) + sizeof(emummc_cfg->partition_cfg));
|
||||
_Static_assert(sizeof(emummc_cfg->base_cfg) + sizeof(emummc_cfg->partition_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand partition config too big!");
|
||||
return 0;
|
||||
} else if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_FILES) {
|
||||
/* Copy path to userpage. */
|
||||
/* Initialize page reference. */
|
||||
if (upage_init(&page_ref, user_address) == 0) {
|
||||
return 2;
|
||||
}
|
||||
/* Copy result output back to user. */
|
||||
if (secure_copy_to_user(&page_ref, user_address, &emummc_cfg->file_cfg, sizeof(emummc_cfg->file_cfg)) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Copy base config afterwards, since this can't fail. */
|
||||
memset(args, 0, sizeof(*args));
|
||||
memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg));
|
||||
_Static_assert(sizeof(emummc_cfg->base_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand base config too big!");
|
||||
return 0;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user