우분투 20.04 qemu patch

우분투 20.04에서 RDK 4.0 빌드할 때, 발생한 에러에 대한 패치를 만드는 마지막 레시피이다. 생각보다는 많이 발생하지 않았지만, Chipset 제조사나 미들웨어에서 권장한 우분투 버전이 아닌 다른 버전에서 빌드환경을 구성하는 일은 정말 피곤한 일이다.

 

qemu 빌드 과정에서 발생하는 아래의 에러는 최신 glibc가 C++ 표준을 따라 <sys/type.h>에서 <sys/sysmacros.h> 제거하여 발생한 문제이다.

| /usr/bin/ld.bfd: qga/commands-posix.o: in function `dev_major_minor':
| /media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/qga/commands-posix.c:656: undefined reference to `major'
| /usr/bin/ld.bfd: /media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/qga/commands-posix.c:657: undefined reference to `minor'
| collect2: error: ld returned 1 exit status
| make: *** [Makefile:327: qemu-ga] Error 1

<sys/sysmacros.h> 추가하여 간단하게 해결이 가능하며, 아래 패치를 적용하면 쉽게 해결할 수 있다.

diff -Nura qemu-2.7.0_old/linux-user/strace.c qemu-2.7.0_new/linux-user/strace.c
--- qemu-2.7.0_old/linux-user/strace.c	2016-09-03 00:34:22.000000000 +0900
+++ qemu-2.7.0_new/linux-user/strace.c	2020-11-03 12:10:06.863161901 +0900
@@ -1,4 +1,5 @@
 #include "qemu/osdep.h"
+#include <sys/sysmacros.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>
 #include <sys/sem.h>
 diff -Nura qemu-2.7.0_old/qga/commands-posix.c qemu-2.7.0_new/qga/commands-posix.c
--- qemu-2.7.0_old/qga/commands-posix.c	2016-09-03 00:34:22.000000000 +0900
+++ qemu-2.7.0_new/qga/commands-posix.c	2020-11-03 12:01:07.739947800 +0900
@@ -12,6 +12,7 @@
  */
 
 #include "qemu/osdep.h"
+#include <sys/sysmacros.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
 #include <dirent.h>

그리고, gettid() 및 stime type이 변경되어 아래와 같은 에러가 발생한다.

/media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/linux-user/syscall.c:206:16: error: static declaration of ‘gettid’ follows non-static declaration
  206 | _syscall0(int, gettid)
      |                ^~~~~~
/media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/linux-user/syscall.c:137:13: note: in definition of macro ‘_syscall0’
  137 | static type name (void)   \
      |             ^~~~
In file included from /usr/include/unistd.h:1170,
                 from /media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/include/qemu/osdep.h:75,
                 from /media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/linux-user/syscall.c:20:
/usr/include/x86_64-linux-gnu/bits/unistd_ext.h:34:16: note: previous declaration of ‘gettid’ was here
   34 | extern __pid_t gettid (void) __THROW;
      |                ^~~~~~
  GEN   arm-softmmu/gdbstub-xml.c
  CC    mips-linux-user/linux-user/syscall.o
/media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/linux-user/syscall.c: In function ‘do_syscall’:
/media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/linux-user/syscall.c:7752:29: warning: implicit declaration of function ‘stime’; did you mean ‘utime’? [-Wimplicit-function-declaration]
 7752 |             ret = get_errno(stime(&host_time));
      |                             ^~~~~
      |                             utime
/media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/linux-user/syscall.c:7752:29: warning: nested extern declaration of ‘stime’ [-Wnested-externs]
  GEN   aarch64-softmmu/gdbstub-xml.c
  CC    mips-softmmu/cpus.o
make[1]: *** [/media/gon/proj/RDK/temp/build-raspberrypi-rdk-hybrid/tmp/work/x86_64-linux/qemu-native/2.7.0-r1/qemu-2.7.0/rules.mak:59: linux-user/syscall.o] Error 1
make: *** [Makefile:204: subdir-i386-linux-user] Error 2
make: *** Waiting for unfinished jobs....

gettid() 함수는 sys_gettid()로 대체하고 time_t는 struct timespec으로 변경한 아래의 패치를 적용하면 에러는 해결된다.

diff -Nura qemu-2.7.0_old/linux-user/syscall.c qemu-2.7.0_new/linux-user/syscall.c
--- qemu-2.7.0_old/linux-user/syscall.c	2016-09-03 00:34:22.000000000 +0900
+++ qemu-2.7.0_new/linux-user/syscall.c	2020-11-03 12:22:19.367511357 +0900
@@ -202,15 +202,9 @@
 #define TARGET_NR__llseek TARGET_NR_llseek
 #endif
 
-#ifdef __NR_gettid
-_syscall0(int, gettid)
-#else
-/* This is a replacement for the host gettid() and must return a host
-   errno. */
-static int gettid(void) {
-    return -ENOSYS;
-}
-#endif
+#define __NR_sys_gettid __NR_gettid
+_syscall0(int, sys_gettid)
+
 #if defined(TARGET_NR_getdents) && defined(__NR_getdents)
 _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
 #endif
@@ -5934,7 +5928,7 @@
     cpu = ENV_GET_CPU(env);
     thread_cpu = cpu;
     ts = (TaskState *)cpu->opaque;
-    info->tid = gettid();
+    info->tid = sys_gettid();
     cpu->host_tid = info->tid;
     task_settid(ts);
     if (info->child_tidptr)
@@ -6062,9 +6056,9 @@
                mapping.  We can't repeat the spinlock hack used above because
                the child process gets its own copy of the lock.  */
             if (flags & CLONE_CHILD_SETTID)
-                put_user_u32(gettid(), child_tidptr);
+                put_user_u32(sys_gettid(), child_tidptr);
             if (flags & CLONE_PARENT_SETTID)
-                put_user_u32(gettid(), parent_tidptr);
+                put_user_u32(sys_gettid(), parent_tidptr);
             ts = (TaskState *)cpu->opaque;
             if (flags & CLONE_SETTLS)
                 cpu_set_tls (env, newtls);
@@ -7746,10 +7740,12 @@
 #ifdef TARGET_NR_stime /* not on alpha */
     case TARGET_NR_stime:
         {
-            time_t host_time;
-            if (get_user_sal(host_time, arg1))
-                goto efault;
-            ret = get_errno(stime(&host_time));
+        	struct timespec ts;
+        	ts.tv_nsec = 0;
+            if (get_user_sal(ts.tv_sec, arg1)) {
+                 return -TARGET_EFAULT;
+            }
+            return get_errno(clock_settime(CLOCK_REALTIME, &ts));
         }
         break;
 #endif
@@ -10880,7 +10876,7 @@
         break;
 #endif
     case TARGET_NR_gettid:
-        ret = get_errno(gettid());
+        ret = get_errno(sys_gettid());
         break;
 #ifdef TARGET_NR_readahead
     case TARGET_NR_readahead: