Index: linux/drivers/char/nvram.c
===================================================================
--- linux.orig/drivers/char/nvram.c	2015-07-12 20:25:02.000000000 +1000
+++ linux/drivers/char/nvram.c	2015-07-12 20:25:03.000000000 +1000
@@ -41,6 +41,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
@@ -178,9 +179,48 @@ static ssize_t nvram_get_size(void)
 	return NVRAM_BYTES;
 }
 
+static ssize_t nvram_read(char *buf, size_t count, loff_t *ppos)
+{
+	char *p = buf;
+	loff_t i;
+
+	spin_lock_irq(&rtc_lock);
+	if (!__nvram_check_checksum()) {
+		spin_unlock_irq(&rtc_lock);
+		return -EIO;
+	}
+	for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p)
+		*p = __nvram_read_byte(i);
+	spin_unlock_irq(&rtc_lock);
+
+	*ppos = i;
+	return p - buf;
+}
+
+static ssize_t nvram_write(char *buf, size_t count, loff_t *ppos)
+{
+	char *p = buf;
+	loff_t i;
+
+	spin_lock_irq(&rtc_lock);
+	if (!__nvram_check_checksum()) {
+		spin_unlock_irq(&rtc_lock);
+		return -EIO;
+	}
+	for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p)
+		__nvram_write_byte(*p, i);
+	__nvram_set_checksum();
+	spin_unlock_irq(&rtc_lock);
+
+	*ppos = i;
+	return p - buf;
+}
+
 const struct nvram_ops arch_nvram_ops = {
 	.read_byte      = nvram_read_byte,
 	.write_byte     = nvram_write_byte,
+	.read           = nvram_read,
+	.write          = nvram_write,
 	.get_size       = nvram_get_size,
 	.set_checksum   = nvram_set_checksum,
 	.initialize     = nvram_initialize,
@@ -215,69 +255,95 @@ static loff_t nvram_misc_llseek(struct f
 static ssize_t nvram_misc_read(struct file *file, char __user *buf,
                                size_t count, loff_t *ppos)
 {
-	unsigned char contents[NVRAM_BYTES];
-	unsigned i = *ppos;
-	unsigned char *tmp;
-
-	spin_lock_irq(&rtc_lock);
+	loff_t i;
+	char __user *p = buf;
 
-	if (!__nvram_check_checksum())
-		goto checksum_err;
-
-	for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
-		*tmp = __nvram_read_byte(i);
-
-	spin_unlock_irq(&rtc_lock);
-
-	if (copy_to_user(buf, contents, tmp - contents))
+	if (!access_ok(VERIFY_WRITE, buf, count))
 		return -EFAULT;
+	if (*ppos >= nvram_size)
+		return 0;
 
-	*ppos = i;
-
-	return tmp - contents;
+	/* If the arch provided a byte range read op, use it. Otherwise
+	 * fall back on the byte-at-a-time accessor.
+	 */
+	if (arch_nvram_ops.read != NULL) {
+		char *tmp;
+		ssize_t ret;
+
+		count = min_t(size_t, count, nvram_size - *ppos);
+		count = min_t(size_t, count, PAGE_SIZE);
+
+		tmp = kmalloc(count, GFP_KERNEL);
+		if (!tmp)
+			return -ENOMEM;
+
+		ret = arch_nvram_ops.read(tmp, count, ppos);
+		if (ret <= 0)
+			goto out;
+
+		if (copy_to_user(buf, tmp, ret)) {
+			*ppos -= ret;
+			ret = -EFAULT;
+		}
+
+out:
+		kfree(tmp);
+		return ret;
+	}
 
-checksum_err:
-	spin_unlock_irq(&rtc_lock);
-	return -EIO;
+	for (i = *ppos; count > 0 && i < nvram_size; ++i, ++p, --count)
+		if (__put_user(arch_nvram_ops.read_byte(i), p))
+			return -EFAULT;
+	*ppos = i;
+	return p - buf;
 }
 
 static ssize_t nvram_misc_write(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
-	unsigned char contents[NVRAM_BYTES];
-	unsigned i = *ppos;
-	unsigned char *tmp;
-
-	if (i >= NVRAM_BYTES)
-		return 0;	/* Past EOF */
-
-	if (count > NVRAM_BYTES - i)
-		count = NVRAM_BYTES - i;
-	if (count > NVRAM_BYTES)
-		return -EFAULT;	/* Can't happen, but prove it to gcc */
+	loff_t i;
+	const char __user *p = buf;
 
-	if (copy_from_user(contents, buf, count))
+	if (!access_ok(VERIFY_READ, buf, count))
 		return -EFAULT;
+	if (*ppos >= nvram_size)
+		return 0;
 
-	spin_lock_irq(&rtc_lock);
-
-	if (!__nvram_check_checksum())
-		goto checksum_err;
-
-	for (tmp = contents; count--; ++i, ++tmp)
-		__nvram_write_byte(*tmp, i);
-
-	__nvram_set_checksum();
+	/* If the arch provided a byte range write op, use it. Otherwise
+	 * fall back on the byte-at-a-time accessor.
+	 */
+	if (arch_nvram_ops.write != NULL) {
+		char *tmp;
+		ssize_t ret;
+
+		count = min_t(size_t, count, nvram_size - *ppos);
+		count = min_t(size_t, count, PAGE_SIZE);
+
+		tmp = kmalloc(count, GFP_KERNEL);
+		if (!tmp)
+			return -ENOMEM;
+
+		if (copy_from_user(tmp, buf, count)) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		ret = arch_nvram_ops.write(tmp, count, ppos);
+
+out:
+		kfree(tmp);
+		return ret;
+	}
 
-	spin_unlock_irq(&rtc_lock);
+	for (i = *ppos; count > 0 && i < nvram_size; ++i, ++p, --count) {
+		char c;
 
+		if (__get_user(c, p))
+			return -EFAULT;
+		arch_nvram_ops.write_byte(c, i);
+	}
 	*ppos = i;
-
-	return tmp - contents;
-
-checksum_err:
-	spin_unlock_irq(&rtc_lock);
-	return -EIO;
+	return p - buf;
 }
 
 static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
