|
@@ -21,6 +21,48 @@
|
|
|
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
|
|
|
#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
|
|
|
|
|
|
+
|
|
|
+/*
|
|
|
+ * Return physical address for virtual address
|
|
|
+ */
|
|
|
+static inline void *load_real_addr(void *addr)
|
|
|
+{
|
|
|
+ unsigned long real_addr;
|
|
|
+
|
|
|
+ asm volatile(
|
|
|
+ " lra %0,0(%1)\n"
|
|
|
+ " jz 0f\n"
|
|
|
+ " la %0,0\n"
|
|
|
+ "0:"
|
|
|
+ : "=a" (real_addr) : "a" (addr) : "cc");
|
|
|
+ return (void *)real_addr;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Copy up to one page to vmalloc or real memory
|
|
|
+ */
|
|
|
+static ssize_t copy_page_real(void *buf, void *src, size_t csize)
|
|
|
+{
|
|
|
+ size_t size;
|
|
|
+
|
|
|
+ if (is_vmalloc_addr(buf)) {
|
|
|
+ BUG_ON(csize >= PAGE_SIZE);
|
|
|
+ /* If buf is not page aligned, copy first part */
|
|
|
+ size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize);
|
|
|
+ if (size) {
|
|
|
+ if (memcpy_real(load_real_addr(buf), src, size))
|
|
|
+ return -EFAULT;
|
|
|
+ buf += size;
|
|
|
+ src += size;
|
|
|
+ }
|
|
|
+ /* Copy second part */
|
|
|
+ size = csize - size;
|
|
|
+ return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0;
|
|
|
+ } else {
|
|
|
+ return memcpy_real(buf, src, csize);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Copy one page from "oldmem"
|
|
|
*
|
|
@@ -32,6 +74,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
|
|
|
size_t csize, unsigned long offset, int userbuf)
|
|
|
{
|
|
|
unsigned long src;
|
|
|
+ int rc;
|
|
|
|
|
|
if (!csize)
|
|
|
return 0;
|
|
@@ -43,11 +86,11 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
|
|
|
src < OLDMEM_BASE + OLDMEM_SIZE)
|
|
|
src -= OLDMEM_BASE;
|
|
|
if (userbuf)
|
|
|
- copy_to_user_real((void __force __user *) buf, (void *) src,
|
|
|
- csize);
|
|
|
+ rc = copy_to_user_real((void __force __user *) buf,
|
|
|
+ (void *) src, csize);
|
|
|
else
|
|
|
- memcpy_real(buf, (void *) src, csize);
|
|
|
- return csize;
|
|
|
+ rc = copy_page_real(buf, (void *) src, csize);
|
|
|
+ return (rc == 0) ? csize : rc;
|
|
|
}
|
|
|
|
|
|
/*
|