Merge tag 'x86_core_for_5.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / arch / x86 / kernel / alternative.c
index a79196f..d374cb3 100644 (file)
@@ -1140,6 +1140,40 @@ void *text_poke_kgdb(void *addr, const void *opcode, size_t len)
        return __text_poke(addr, opcode, len);
 }
 
+/**
+ * text_poke_copy - Copy instructions into (an unused part of) RX memory
+ * @addr: address to modify
+ * @opcode: source of the copy
+ * @len: length to copy, could be more than 2x PAGE_SIZE
+ *
+ * Not safe against concurrent execution; useful for JITs to dump
+ * new code blocks into unused regions of RX memory. Can be used in
+ * conjunction with synchronize_rcu_tasks() to wait for existing
+ * execution to quiesce after having made sure no existing functions
+ * pointers are live.
+ */
+void *text_poke_copy(void *addr, const void *opcode, size_t len)
+{
+       unsigned long start = (unsigned long)addr;
+       size_t patched = 0;
+
+       if (WARN_ON_ONCE(core_kernel_text(start)))
+               return NULL;
+
+       mutex_lock(&text_mutex);
+       while (patched < len) {
+               unsigned long ptr = start + patched;
+               size_t s;
+
+               s = min_t(size_t, PAGE_SIZE * 2 - offset_in_page(ptr), len - patched);
+
+               __text_poke((void *)ptr, opcode + patched, s);
+               patched += s;
+       }
+       mutex_unlock(&text_mutex);
+       return addr;
+}
+
 static void do_sync_core(void *info)
 {
        sync_core();