1From fa9bcabe2387bb230ef82d62827ad6f93b8a1e61 Mon Sep 17 00:00:00 2001
2From: Frederic Konrad <fkonrad@amd.com>
3Date: Wed, 17 Jan 2024 18:15:06 +0000
4Subject: [PATCH 1/2] linux-user/*: workaround for missing MAP_FIXED_NOREPLACE
5
6QEMU v8.1.0 recently requires MAP_FIXED_NOREPLACE flags implementation for mmap.
7
8This is missing from ubuntu 18.04, thus this patch catches the mmap calls which
9could use that new flag and forwards them to mmap when MAP_FIXED_NOREPLACE
10flag isn't set or emulates them by checking the returned address w.r.t the
11requested address.
12
13Signed-off-by: Frederic Konrad <fkonrad@amd.com>
14Signed-off-by: Francisco Iglesias <francisco.iglesias@amd.com>
15
16Upstream-Status: Inappropriate [OE specific]
17
18The upstream only supports the last two major releases of an OS.  The ones
19they have declared all have kernel 4.17 or newer.
20
21See:
22https://xilinx.slack.com/archives/D04G2647CTV/p1705074697942019
23
24https://www.qemu.org/docs/master/about/build-platforms.html
25
26 The project aims to support the most recent major version at all times for up
27 to five years after its initial release. Support for the previous major
28 version will be dropped 2 years after the new major version is released or
29 when the vendor itself drops support, whichever comes first.
30
31Signed-off-by: Mark Hatle <mark.hatle@amd.com>
32---
33 linux-user/elfload.c    |  7 +++--
34 linux-user/meson.build  |  1 +
35 linux-user/mmap-fixed.c | 63 +++++++++++++++++++++++++++++++++++++++++
36 linux-user/mmap-fixed.h | 39 +++++++++++++++++++++++++
37 linux-user/mmap.c       | 31 +++++++++++---------
38 linux-user/syscall.c    |  1 +
39 6 files changed, 125 insertions(+), 17 deletions(-)
40 create mode 100644 linux-user/mmap-fixed.c
41 create mode 100644 linux-user/mmap-fixed.h
42
43Index: qemu-8.2.1/linux-user/elfload.c
44===================================================================
45--- qemu-8.2.1.orig/linux-user/elfload.c
46+++ qemu-8.2.1/linux-user/elfload.c
47@@ -22,6 +22,7 @@
48 #include "qemu/error-report.h"
49 #include "target_signal.h"
50 #include "accel/tcg/debuginfo.h"
51+#include "mmap-fixed.h"
52
53 #ifdef TARGET_ARM
54 #include "target/arm/cpu-features.h"
55@@ -2765,9 +2766,9 @@ static abi_ulong create_elf_tables(abi_u
56 static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
57 {
58     size_t size = addr_last - addr + 1;
59-    void *p = mmap((void *)addr, size, PROT_NONE,
60-                   MAP_ANONYMOUS | MAP_PRIVATE |
61-                   MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
62+    void *p = mmap_fixed_noreplace((void *)addr, size, PROT_NONE,
63+                                   MAP_ANONYMOUS | MAP_PRIVATE |
64+                                   MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
65     int ret;
66
67     if (p == MAP_FAILED) {
68Index: qemu-8.2.1/linux-user/meson.build
69===================================================================
70--- qemu-8.2.1.orig/linux-user/meson.build
71+++ qemu-8.2.1/linux-user/meson.build
72@@ -14,6 +14,7 @@ linux_user_ss.add(files(
73   'linuxload.c',
74   'main.c',
75   'mmap.c',
76+  'mmap-fixed.c',
77   'signal.c',
78   'strace.c',
79   'syscall.c',
80Index: qemu-8.2.1/linux-user/mmap-fixed.c
81===================================================================
82--- /dev/null
83+++ qemu-8.2.1/linux-user/mmap-fixed.c
84@@ -0,0 +1,63 @@
85+/*
86+ * Workaround for MAP_FIXED_NOREPLACE
87+ *
88+ * Copyright (c) 2024, Advanced Micro Devices, Inc.
89+ * Developed by Fred Konrad <fkonrad@amd.com>
90+ *
91+ * Permission is hereby granted, free of charge, to any person obtaining a copy
92+ * of this software and associated documentation files (the "Software"), to deal
93+ * in the Software without restriction, including without limitation the rights
94+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
95+ * copies of the Software, and to permit persons to whom the Software is
96+ * furnished to do so, subject to the following conditions:
97+ *
98+ * The above copyright notice and this permission notice shall be included in
99+ * all copies or substantial portions of the Software.
100+ *
101+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
102+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
103+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
104+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
105+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
106+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
107+ * THE SOFTWARE.
108+ */
109+
110+#include <sys/mman.h>
111+#include <errno.h>
112+
113+#ifndef MAP_FIXED_NOREPLACE
114+#include "mmap-fixed.h"
115+
116+void *mmap_fixed_noreplace(void *addr, size_t len, int prot, int flags,
117+                                  int fd, off_t offset)
118+{
119+    void *retaddr;
120+
121+    if (!(flags & MAP_FIXED_NOREPLACE)) {
122+        /* General case, use the regular mmap.  */
123+        return mmap(addr, len, prot, flags, fd, offset);
124+    }
125+
126+    /* Since MAP_FIXED_NOREPLACE is not implemented, try to emulate it.  */
127+    flags = flags & ~(MAP_FIXED_NOREPLACE | MAP_FIXED);
128+    retaddr = mmap(addr, len, prot, flags, fd, offset);
129+    if ((retaddr == addr) || (retaddr == MAP_FAILED)) {
130+        /*
131+         * Either the map worked and we get the good address so it can be
132+         * returned, or it failed and would have failed the same with
133+         * MAP_FIXED*, in which case return MAP_FAILED.
134+         */
135+        return retaddr;
136+    } else {
137+        /*
138+         * Page has been mapped but not at the requested address.. unmap it and
139+         * return EEXIST.
140+         */
141+        munmap(retaddr, len);
142+        errno = EEXIST;
143+        return MAP_FAILED;
144+    }
145+}
146+
147+#endif
148Index: qemu-8.2.1/linux-user/mmap-fixed.h
149===================================================================
150--- /dev/null
151+++ qemu-8.2.1/linux-user/mmap-fixed.h
152@@ -0,0 +1,39 @@
153+/*
154+ * Workaround for MAP_FIXED_NOREPLACE
155+ *
156+ * Copyright (c) 2024, Advanced Micro Devices, Inc.
157+ * Developed by Fred Konrad <fkonrad@amd.com>
158+ *
159+ * Permission is hereby granted, free of charge, to any person obtaining a copy
160+ * of this software and associated documentation files (the "Software"), to deal
161+ * in the Software without restriction, including without limitation the rights
162+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
163+ * copies of the Software, and to permit persons to whom the Software is
164+ * furnished to do so, subject to the following conditions:
165+ *
166+ * The above copyright notice and this permission notice shall be included in
167+ * all copies or substantial portions of the Software.
168+ *
169+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
172+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
173+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
174+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
175+ * THE SOFTWARE.
176+ */
177+
178+#ifndef MMAP_FIXED_H
179+#define MMAP_FIXED_H
180+
181+#ifndef MAP_FIXED_NOREPLACE
182+#define MAP_FIXED_NOREPLACE 0x100000
183+
184+void *mmap_fixed_noreplace(void *addr, size_t len, int prot, int flags,
185+                           int fd, off_t offset);
186+
187+#else /* MAP_FIXED_NOREPLACE */
188+#define mmap_fixed_noreplace mmap
189+#endif /* MAP_FIXED_NOREPLACE */
190+
191+#endif /* MMAP_FIXED_H */
192Index: qemu-8.2.1/linux-user/mmap.c
193===================================================================
194--- qemu-8.2.1.orig/linux-user/mmap.c
195+++ qemu-8.2.1/linux-user/mmap.c
196@@ -25,6 +25,7 @@
197 #include "user-mmap.h"
198 #include "target_mman.h"
199 #include "qemu/interval-tree.h"
200+#include "mmap-fixed.h"
201
202 #ifdef TARGET_ARM
203 #include "target/arm/cpu-features.h"
204@@ -273,7 +274,7 @@ int target_mprotect(abi_ulong start, abi
205 static int do_munmap(void *addr, size_t len)
206 {
207     if (reserved_va) {
208-        void *ptr = mmap(addr, len, PROT_NONE,
209+        void *ptr =  mmap_fixed_noreplace(addr, len, PROT_NONE,
210                          MAP_FIXED | MAP_ANONYMOUS
211                          | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
212         return ptr == addr ? 0 : -1;
213@@ -319,9 +320,9 @@ static bool mmap_frag(abi_ulong real_sta
214          * outside of the fragment we need to map.  Allocate a new host
215          * page to cover, discarding whatever else may have been present.
216          */
217-        void *p = mmap(host_start, qemu_host_page_size,
218-                       target_to_host_prot(prot),
219-                       flags | MAP_ANONYMOUS, -1, 0);
220+        void *p = mmap_fixed_noreplace(host_start, qemu_host_page_size,
221+                                       target_to_host_prot(prot),
222+                                       flags | MAP_ANONYMOUS, -1, 0);
223         if (p != host_start) {
224             if (p != MAP_FAILED) {
225                 munmap(p, qemu_host_page_size);
226@@ -420,8 +421,9 @@ abi_ulong mmap_find_vma(abi_ulong start,
227          *  - mremap() with MREMAP_FIXED flag
228          *  - shmat() with SHM_REMAP flag
229          */
230-        ptr = mmap(g2h_untagged(addr), size, PROT_NONE,
231-                   MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
232+        ptr = mmap_fixed_noreplace(g2h_untagged(addr), size, PROT_NONE,
233+                                   MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
234+                                   -1, 0);
235
236         /* ENOMEM, if host address space has no memory */
237         if (ptr == MAP_FAILED) {
238@@ -615,16 +617,16 @@ abi_long target_mmap(abi_ulong start, ab
239          * especially important if qemu_host_page_size >
240          * qemu_real_host_page_size.
241          */
242-        p = mmap(g2h_untagged(start), host_len, host_prot,
243-                 flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
244+        p = mmap_fixed_noreplace(g2h_untagged(start), host_len, host_prot,
245+                                 flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
246         if (p == MAP_FAILED) {
247             goto fail;
248         }
249         /* update start so that it points to the file position at 'offset' */
250         host_start = (uintptr_t)p;
251         if (!(flags & MAP_ANONYMOUS)) {
252-            p = mmap(g2h_untagged(start), len, host_prot,
253-                     flags | MAP_FIXED, fd, host_offset);
254+            p = mmap_fixed_noreplace(g2h_untagged(start), len, host_prot,
255+                                     flags | MAP_FIXED, fd, host_offset);
256             if (p == MAP_FAILED) {
257                 munmap(g2h_untagged(start), host_len);
258                 goto fail;
259@@ -749,8 +751,9 @@ abi_long target_mmap(abi_ulong start, ab
260             len1 = real_last - real_start + 1;
261             want_p = g2h_untagged(real_start);
262
263-            p = mmap(want_p, len1, target_to_host_prot(target_prot),
264-                     flags, fd, offset1);
265+            p = mmap_fixed_noreplace(want_p, len1,
266+                                     target_to_host_prot(target_prot),
267+                                     flags, fd, offset1);
268             if (p != want_p) {
269                 if (p != MAP_FAILED) {
270                     munmap(p, len1);
271Index: qemu-8.2.1/linux-user/syscall.c
272===================================================================
273--- qemu-8.2.1.orig/linux-user/syscall.c
274+++ qemu-8.2.1/linux-user/syscall.c
275@@ -145,6 +145,7 @@
276 #include "qapi/error.h"
277 #include "fd-trans.h"
278 #include "cpu_loop-common.h"
279+#include "mmap-fixed.h"
280
281 #ifndef CLONE_IO
282 #define CLONE_IO                0x80000000      /* Clone io context */
283