From 4c16cecbbb127fd05fb68a6bfa3060503117e7ba Mon Sep 17 00:00:00 2001 From: glevand Date: Sat, 5 Oct 2013 13:55:39 +0200 Subject: [PATCH] add new memory buffer and export it under as 'buf' in filesystem; implement 32bit address because some SPU modules use 32bit addresses to access PPU buffers --- spuisofs.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/spuisofs.c b/spuisofs.c index 319c2cd..ed8d599 100644 --- a/spuisofs.c +++ b/spuisofs.c @@ -2,7 +2,7 @@ /* * PS3 spuisofs * - * Copyright (C) 2012 glevand + * Copyright (C) 2012-2013 glevand * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -100,6 +100,7 @@ static unsigned int spuisofs_spe_virq[4]; static void *spuisofs_spe_app; static void *spuisofs_spe_arg1; static void *spuisofs_spe_arg2; +static void *spuisofs_buf; static unsigned int spuisofs_spe_slb_index; @@ -112,12 +113,18 @@ module_param(spuisofs_spe_arg1_size, ulong, 0); static unsigned long spuisofs_spe_arg2_size = 1024 * 1024; module_param(spuisofs_spe_arg2_size, ulong, 0); +static unsigned long spuisofs_buf_size = 1024 * 1024; +module_param(spuisofs_buf_size, ulong, 0); + static unsigned long spuisofs_spe_trans_notify_mask = 0xf; module_param(spuisofs_spe_trans_notify_mask, ulong, 0); static unsigned long spuisofs_spe_resource_id = 6; module_param(spuisofs_spe_resource_id, ulong, 0); +static int spuisofs_buf_addr_32bit = 0; +module_param(spuisofs_buf_addr_32bit, int, 0); + /* * spuisofs_spe_regs_read */ @@ -295,9 +302,15 @@ static ssize_t spuisofs_info_read(struct file *file, char __user *buffer, { char buf[256]; size_t len; + unsigned long buf_addr; - len = sprintf(buf, "arg1 %lx\narg2 %lx\n", - (unsigned long) spuisofs_spe_arg1, (unsigned long) spuisofs_spe_arg2); + buf_addr = (unsigned long) spuisofs_buf; + if (spuisofs_buf_addr_32bit) + buf_addr &= 0xfffffffful; + + len = sprintf(buf, "arg1 %lx\narg2 %lx\nbuf %lx\n", + (unsigned long) spuisofs_spe_arg1, (unsigned long) spuisofs_spe_arg2, + buf_addr); return simple_read_from_buffer(buffer, size, pos, buf, len); } @@ -545,6 +558,7 @@ static int spuisofs_fill_super(struct super_block *sb, void *data, int silent) { "app", &spuisofs_mem_fops, 0666, spuisofs_spe_app_size, 0, spuisofs_spe_app, }, { "arg1", &spuisofs_mem_fops, 0666, spuisofs_spe_arg1_size, 0, spuisofs_spe_arg1, }, { "arg2", &spuisofs_mem_fops, 0666, spuisofs_spe_arg2_size, 0, spuisofs_spe_arg2, }, + { "buf", &spuisofs_mem_fops, 0666, spuisofs_buf_size, 0, spuisofs_buf, }, { "info", &spuisofs_info_fops, 0444, 0, 0, NULL, }, { "run", &spuisofs_run_fops, 0222, sizeof(struct spuisofs_run_args), 0, NULL, }, { "cont", &spuisofs_cont_fops, 0222, 0, 0, NULL, }, @@ -587,7 +601,7 @@ static int spuisofs_fill_super(struct super_block *sb, void *data, int silent) static irqreturn_t spuisofs_spe_interrupt(int irq, void *data) { u64 status; - u64 ea, dsisr, esid, vsid; + u64 ea, ea_full, dsisr, esid, vsid, buf_addr; u64 puint_mb_R; u32 spu_status_R; u64 spe_execution_status; @@ -622,10 +636,19 @@ static irqreturn_t spuisofs_spe_interrupt(int irq, void *data) if (status & CLASS1_SEGMENT_FAULT_INTR) { ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW); + ea_full = ea; + + buf_addr = (u64) spuisofs_buf; + if (spuisofs_buf_addr_32bit) + buf_addr &= 0xfffffffful; + + if ((ea >= buf_addr) && (ea < (buf_addr + spuisofs_buf_size))) + ea_full = (u64) spuisofs_buf + (buf_addr - ea); + esid = (ea & ESID_MASK) | SLB_ESID_V; - vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | MMU_PAGE_4K; + vsid = (get_kernel_vsid(ea_full, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | MMU_PAGE_4K; - printk(KERN_INFO"spuisofs: data segment fault at %llx\n", ea); + printk(KERN_INFO"spuisofs: data segment fault at %llx (%llx)\n", ea, ea_full); err = lv1_undocumented_function_62(spuisofs_spe_id, 0, spuisofs_spe_slb_index, esid, vsid); if (err) { @@ -640,12 +663,20 @@ static irqreturn_t spuisofs_spe_interrupt(int irq, void *data) if (status & CLASS1_STORAGE_FAULT_INTR) { ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW); + ea_full = ea; dsisr = in_be64(&spuisofs_spe_shadow->mfc_dsisr_RW); - printk(KERN_INFO"spuisofs: data storage fault at %llx\n", ea); + buf_addr = (u64) spuisofs_buf; + if (spuisofs_buf_addr_32bit) + buf_addr &= 0xfffffffful; + + if ((ea >= buf_addr) && (ea < (buf_addr + spuisofs_buf_size))) + ea_full = (u64) spuisofs_buf + (buf_addr - ea); + + printk(KERN_INFO"spuisofs: data storage fault at %llx (%llx)\n", ea, ea_full); if (dsisr & MFC_DSISR_PTE_NOT_FOUND) { - err = hash_page(ea, _PAGE_PRESENT, 0x300); + err = hash_page(ea_full, _PAGE_PRESENT, 0x300); if (err) { printk(KERN_INFO"spuisofs: hash_page failed with %d\n", err); goto out; @@ -927,14 +958,26 @@ static struct dentry *spuisofs_mount(struct file_system_type *fs_type, memset(spuisofs_spe_arg2, 0, spuisofs_spe_arg2_size); + spuisofs_buf = vmalloc_user(spuisofs_buf_size); + if (!spuisofs_buf) { + err = -ENOMEM; + goto fail_free_spe_arg2; + } + + memset(spuisofs_buf, 0, spuisofs_buf_size); + root = mount_single(fs_type, flags, data, spuisofs_fill_super); if (IS_ERR(root)) { err = PTR_ERR(root); - goto fail_free_spe_arg2; + goto fail_free_buf; } return (root); +fail_free_buf: + + vfree(spuisofs_buf); + fail_free_spe_arg2: vfree(spuisofs_spe_arg2); @@ -964,6 +1007,7 @@ static void spuisofs_kill_sb(struct super_block *sb) vfree(spuisofs_spe_app); vfree(spuisofs_spe_arg1); vfree(spuisofs_spe_arg2); + vfree(spuisofs_buf); spuisofs_destruct_spe(); } -- 2.11.4.GIT