diff -Nru skiboot-6.5.2/debian/changelog skiboot-6.5.2/debian/changelog
--- skiboot-6.5.2/debian/changelog	2020-01-15 07:56:04.000000000 -0600
+++ skiboot-6.5.2/debian/changelog	2020-12-07 16:03:03.000000000 -0600
@@ -1,3 +1,14 @@
+skiboot (6.5.2-1ubuntu0.20.04.1) focal; urgency=medium
+
+  * opal-prd: mmap(range:ibm,hbrt-code-image,...) fails with EPERM
+     (LP: #1905393) opal-prd fails to start
+     d/patches/0005-fix-opal-prd-fail-with-EPERM.patch
+  * opal-prd: Have a worker process handle page offlining
+     (LP: #1904585) Have a worker process handle page offlining
+     d/patches/0006-fix-opal-prd-have-worker-process-handle-page-offlining.patch
+
+ -- Matthieu Clemenceau <matthieu.clemenceau@canonical.com>  Mon, 07 Dec 2020 16:03:03 -0600
+
 skiboot (6.5.2-1) unstable; urgency=medium
 
   * Update to new upstream version 6.5.2.
diff -Nru skiboot-6.5.2/debian/patches/0005-fix-opal-prd-fail-with-EPERM.patch skiboot-6.5.2/debian/patches/0005-fix-opal-prd-fail-with-EPERM.patch
--- skiboot-6.5.2/debian/patches/0005-fix-opal-prd-fail-with-EPERM.patch	1969-12-31 18:00:00.000000000 -0600
+++ skiboot-6.5.2/debian/patches/0005-fix-opal-prd-fail-with-EPERM.patch	2020-12-07 16:02:48.000000000 -0600
@@ -0,0 +1,60 @@
+--- a/external/opal-prd/opal-prd.c
++++ b/external/opal-prd/opal-prd.c
+@@ -947,7 +947,9 @@
+ static int map_hbrt_physmem(struct opal_prd_ctx *ctx, const char *name)
+ {
+ 	struct prd_range *range;
++	int rc;
+ 	void *buf;
++	void *ro_buf;
+ 
+ 	range = find_range(name, 0);
+ 	if (!range) {
+@@ -955,15 +957,45 @@
+ 		return -1;
+ 	}
+ 
+-	buf = mmap(NULL, range->size, PROT_READ | PROT_WRITE | PROT_EXEC,
++	ro_buf = mmap(NULL, range->size, PROT_READ,
+ 			MAP_PRIVATE, ctx->fd, range->physaddr);
+-	if (buf == MAP_FAILED) {
++	if (ro_buf == MAP_FAILED) {
+ 		pr_log(LOG_ERR, "IMAGE: mmap(range:%s, "
+ 				"phys:0x%016lx, size:0x%016lx) failed: %m",
+ 				name, range->physaddr, range->size);
+ 		return -1;
+ 	}
+ 
++	buf = mmap(NULL, range->size, PROT_READ | PROT_WRITE,
++			MAP_SHARED | MAP_ANONYMOUS, -1 , 0);
++	if (buf == MAP_FAILED) {
++		pr_log(LOG_ERR, "IMAGE: anon mmap(size:0x%016lx) failed: %m",
++				range->size);
++		return -1;
++	}
++
++	memcpy(buf, ro_buf, range->size);
++
++	rc = munmap(ro_buf, range->size);
++	if (rc < 0) {
++		pr_log(LOG_ERR, "IMAGE: munmap("
++				"phys:0x%016lx, size:0x%016lx) failed: %m",
++				range->physaddr, range->size);
++		return -1;
++	}
++
++	/*
++	 * FIXME: We shouldn't be mapping the memory as RWX, but HBRT appears to
++	 * require the ability to write into the image at runtime.
++	 */
++	rc = mprotect(buf, range->size, PROT_READ | PROT_WRITE | PROT_EXEC);
++	if (rc < 0) {
++		pr_log(LOG_ERR, "IMAGE: mprotect(phys:%p, "
++			"size:0x%016lx, rwx) failed: %m",
++			buf, range->size);
++		return -1;
++	}
++
+ 	ctx->code_addr = buf;
+ 	ctx->code_size = range->size;
+ 	return 0;
diff -Nru skiboot-6.5.2/debian/patches/0006-fix-opal-prd-have-worker-process-handle-page-offlining.patch skiboot-6.5.2/debian/patches/0006-fix-opal-prd-have-worker-process-handle-page-offlining.patch
--- skiboot-6.5.2/debian/patches/0006-fix-opal-prd-have-worker-process-handle-page-offlining.patch	1969-12-31 18:00:00.000000000 -0600
+++ skiboot-6.5.2/debian/patches/0006-fix-opal-prd-have-worker-process-handle-page-offlining.patch	2020-12-07 16:03:03.000000000 -0600
@@ -0,0 +1,128 @@
+--- a/external/opal-prd/opal-prd.c
++++ b/external/opal-prd/opal-prd.c
+@@ -27,6 +27,7 @@
+ #include <stdarg.h>
+ #include <time.h>
+ #include <poll.h>
++#include <signal.h>
+ #include <dirent.h>
+ 
+ #include <endian.h>
+@@ -695,13 +696,42 @@
+ 	return rc;
+ }
+ 
++static int memory_error_worker(const char *sysfsfile, const char *type,
++			       uint64_t i_start_addr, uint64_t i_endAddr)
++{
++	int memfd, rc, n, ret = 0;
++	char buf[ADDR_STRING_SZ];
++	uint64_t addr;
++
++	memfd = open(sysfsfile, O_WRONLY);
++	if (memfd < 0) {
++		pr_log(LOG_CRIT, "MEM: Failed to offline memory! "
++				"Unable to open sysfs node %s: %m", sysfsfile);
++		return -1;
++	}
++
++	for (addr = i_start_addr; addr <= i_endAddr; addr += ctx->page_size) {
++		n = snprintf(buf, ADDR_STRING_SZ, "0x%lx", addr);
++		rc = write(memfd, buf, n);
++		if (rc != n) {
++			pr_log(LOG_CRIT, "MEM: Failed to offline memory! "
++					"page addr: %016lx type: %s: %m",
++				addr, type);
++			ret = 1;
++		}
++	}
++	pr_log(LOG_CRIT, "MEM: Offlined %016lx,%016lx, type %s: %m\n",
++			i_start_addr, addr, type);
++
++	close(memfd);
++	return ret;
++}
++
+ int hservice_memory_error(uint64_t i_start_addr, uint64_t i_endAddr,
+ 		enum MemoryError_t i_errorType)
+ {
+ 	const char *sysfsfile, *typestr;
+-	char buf[ADDR_STRING_SZ];
+-	int memfd, rc, n, ret = 0;
+-	uint64_t addr;
++	pid_t pid;
+ 
+ 	switch(i_errorType) {
+ 	case MEMORY_ERROR_CE:
+@@ -721,26 +751,21 @@
+ 	pr_log(LOG_ERR, "MEM: Memory error: range %016lx-%016lx, type: %s",
+ 			i_start_addr, i_endAddr, typestr);
+ 
++	/*
++	 * HBRT expects the memory offlining process to happen in the background
++	 * after the notification is delivered.
++	 */
++	pid = fork();
++	if (pid > 0)
++		exit(memory_error_worker(sysfsfile, typestr, i_start_addr, i_endAddr));
+ 
+-	memfd = open(sysfsfile, O_WRONLY);
+-	if (memfd < 0) {
+-		pr_log(LOG_CRIT, "MEM: Failed to offline memory! "
+-				"Unable to open sysfs node %s: %m", sysfsfile);
++	if (pid < 0) {
++		perror("MEM: unable to fork worker to offline memory!\n");
+ 		return -1;
+ 	}
+ 
+-	for (addr = i_start_addr; addr <= i_endAddr; addr += ctx->page_size) {
+-		n = snprintf(buf, ADDR_STRING_SZ, "0x%lx", addr);
+-		rc = write(memfd, buf, n);
+-		if (rc != n) {
+-			pr_log(LOG_CRIT, "MEM: Failed to offline memory! "
+-					"page addr: %016lx type: %d: %m",
+-				addr, i_errorType);
+-			ret = rc;
+-		}
+-	}
+-
+-	return ret;
++	pr_log(LOG_INFO, "MEM: forked off %d to handle mem error\n", pid);
++	return 0;
+ }
+ 
+ uint64_t hservice_get_interface_capabilities(uint64_t set)
+@@ -2143,6 +2168,10 @@
+ 	return 0;
+ }
+ 
++static struct sigaction sigchild_action = {
++	.sa_flags = SA_NOCLDWAIT | SA_RESTART,
++	.sa_handler = SIG_DFL,
++};
+ 
+ static int run_prd_daemon(struct opal_prd_ctx *ctx)
+ {
+@@ -2270,6 +2299,22 @@
+ 		pr_debug("SCOM:  f00f: %lx", be64toh(val));
+ 	}
+ 
++	/*
++	 * Setup the SIGCHLD handler to automatically reap the worker threads
++	 * we use for memory offlining. We can't do this earlier since the
++	 * modprobe helper spawns workers and wants to check their exit status
++	 * with waitpid(). Auto-reaping breaks that so enable it just before
++	 * entering the attn loop.
++	 *
++	 * We also setup system call restarting on SIGCHLD since opal-prd
++	 * doesn't make any real attempt to handle blocking functions exiting
++	 * due to EINTR.
++	 */
++	if (sigaction(SIGCHLD, &sigchild_action, NULL)) {
++		pr_log(LOG_ERR, "CTRL: Failed to register signal handler %m\n");
++		return -1;
++	}
++
+ 	run_attn_loop(ctx);
+ 	rc = 0;
+ 
diff -Nru skiboot-6.5.2/debian/patches/series skiboot-6.5.2/debian/patches/series
--- skiboot-6.5.2/debian/patches/series	2020-01-15 07:56:04.000000000 -0600
+++ skiboot-6.5.2/debian/patches/series	2020-12-07 16:03:03.000000000 -0600
@@ -2,3 +2,5 @@
 0002-Use-default-m32-m64-gcc-flag.patch
 0003-Use-file-operation-used-on-x86-for-ARCH_UNKNOWN.patch
 0004-Move-sbin-commands-manpages-from-section-1-to-8.patch
+0005-fix-opal-prd-fail-with-EPERM.patch
+0006-fix-opal-prd-have-worker-process-handle-page-offlining.patch
