bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH gnumach] Update the 64bit RPC ABI to be simpler (v2)


From: Flavio Cruz
Subject: [PATCH gnumach] Update the 64bit RPC ABI to be simpler (v2)
Date: Tue, 13 Jun 2023 00:01:25 -0400

* Make full use of the 8 bytes available in mach_msg_type_t by moving
  into the unused 4 bytes. This allows us to use 32bits for
  mach_msg_type_number_t whether we use the longform or not.
* Make mach_msg_type_long_t exactly the same as mach_msg_type_t.
  Updating MiG is strongly encouraged since it will generate better code
  to handle this new format.

After this change, any compatibility with compiled binaries for Hurd x86_64
will break since the message format is different. However, the new
schema simplifies the overall ABI, without having "holes" and also
avoids the need to have a 16 byte mach_msg_type_long_t.

Was able to boot a basic system up to a bash shell.
---
 include/mach/message.h | 52 ++++++++++++++++++++++---
 ipc/ipc_kmsg.c         |  4 ++
 x86_64/copy_user.c     | 88 ++++++++++++++++++++++++++++++++++--------
 3 files changed, 123 insertions(+), 21 deletions(-)

diff --git a/include/mach/message.h b/include/mach/message.h
index 0eab9d41..2177343a 100644
--- a/include/mach/message.h
+++ b/include/mach/message.h
@@ -222,6 +222,30 @@ typedef unsigned int mach_msg_type_size_t;
 typedef natural_t  mach_msg_type_number_t;
 
 typedef struct  {
+#ifdef __x86_64__
+    /*
+     * For 64 bits, this struct is 8 bytes long so we
+     * can pack the same amount of information as mach_msg_type_long_t.
+     * Note that for 64 bit userland, msgt_size only needs to be 8 bits long
+     * but for kernel compatibility with 32 bit userland we allow it to be
+     * 16 bits long.
+     *
+     * Effectively, we don't need mach_msg_type_long_t but we are keeping it
+     * for a while to make the code similar between 32 and 64 bits.
+     *
+     * We also keep the msgt_longform bit around simply because it makes it
+     * very easy to convert messages from a 32 bit userland into a 64 bit
+     * kernel. Otherwise, we would have to replicate some of the MiG logic
+     * internally in the kernel.
+     */
+    unsigned int       msgt_inline : 1,
+                       msgt_longform : 1,
+                       msgt_deallocate : 1,
+                       msgt_name : 8,
+                       msgt_size : 16,
+                       msgt_unused : 5;
+    mach_msg_type_number_t   msgt_number;
+#else
     unsigned int       msgt_name : 8,
                        msgt_size : 8,
                        msgt_number : 12,
@@ -229,20 +253,38 @@ typedef struct  {
                        msgt_longform : 1,
                        msgt_deallocate : 1,
                        msgt_unused : 1;
-#ifdef __x86_64__
-    /* TODO: We want to eventually use this in favor of mach_msg_type_long_t
-     * as it makes the mach_msg protocol require only mach_msg_type_t. */
-    mach_msg_type_number_t   unused_msgtl_number;
 #endif
 } __attribute__ ((aligned (__alignof__ (uintptr_t)))) mach_msg_type_t;
 
-typedef        struct  {
+typedef struct {
+#ifdef __x86_64__
+    union {
+        /* On x86_64 this is equivalent to mach_msg_type_t so use
+         * union to overlay with the old field names.  */
+        mach_msg_type_t        msgtl_header;
+        struct {
+            unsigned int       msgtl_inline : 1,
+                    msgtl_longform : 1,
+                    msgtl_deallocate : 1,
+                    msgtl_name : 8,
+                    msgtl_size : 16,
+                    msgtl_unused : 5;
+            mach_msg_type_number_t   msgtl_number;
+        };
+    };
+#else
     mach_msg_type_t    msgtl_header;
     unsigned short     msgtl_name;
     unsigned short     msgtl_size;
     natural_t          msgtl_number;
+#endif
 } __attribute__ ((aligned (__alignof__ (uintptr_t)))) mach_msg_type_long_t;
 
+#ifdef __x86_64__
+_Static_assert (sizeof (mach_msg_type_t) == sizeof (mach_msg_type_long_t),
+                "mach_msg_type_t and mach_msg_type_long_t need to have the 
same size.");
+#endif
+
 /*
  *     Known values for the msgt_name field.
  *
diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c
index 1988da45..d1c4675c 100644
--- a/ipc/ipc_kmsg.c
+++ b/ipc/ipc_kmsg.c
@@ -1343,9 +1343,11 @@ ipc_kmsg_copyin_body(
                is_port = MACH_MSG_TYPE_PORT_ANY(name);
 
                if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
+#ifndef __x86_64__
                    (longform && ((type->msgtl_header.msgt_name != 0) ||
                                  (type->msgtl_header.msgt_size != 0) ||
                                  (type->msgtl_header.msgt_number != 0))) ||
+#endif
                    (((mach_msg_type_t*)type)->msgt_unused != 0) ||
                    (dealloc && is_inline)) {
                        ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
@@ -2833,9 +2835,11 @@ ipc_msg_print(mach_msg_header_t *msgh)
                is_port = MACH_MSG_TYPE_PORT_ANY(name);
 
                if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
+#ifndef __x86_64__
                    (longform && ((type->msgtl_header.msgt_name != 0) ||
                                  (type->msgtl_header.msgt_size != 0) ||
                                  (type->msgtl_header.msgt_number != 0))) ||
+#endif
                    (((mach_msg_type_t*)type)->msgt_unused != 0) ||
                    (dealloc && is_inline)) {
                        db_printf("*** invalid type\n");
diff --git a/x86_64/copy_user.c b/x86_64/copy_user.c
index 6ff50e12..548d9d7d 100644
--- a/x86_64/copy_user.c
+++ b/x86_64/copy_user.c
@@ -87,12 +87,74 @@ static inline void unpack_msg_type(vm_offset_t addr,
     }
 }
 
+#ifdef USER32
+static inline void mach_msg_user_type_to_kernel(const mach_msg_user_type_t *u,
+    mach_msg_type_t* k) {
+  k->msgt_name = u->msgt_name;
+  k->msgt_size = u->msgt_size;
+  k->msgt_number = u->msgt_number;
+  k->msgt_inline = u->msgt_inline;
+  k->msgt_longform = u->msgt_longform;
+  k->msgt_deallocate = u->msgt_deallocate;
+  k->msgt_unused = 0;
+}
+
+static inline void mach_msg_user_type_to_kernel_long(const 
mach_msg_user_type_long_t *u,
+    mach_msg_type_long_t* k) {
+  const mach_msg_type_long_t kernel = {
+    .msgtl_header = {
+      .msgt_name = u->msgtl_name,
+      .msgt_size = u->msgtl_size,
+      .msgt_number = u->msgtl_number,
+      .msgt_inline = u->msgtl_header.msgt_inline,
+      .msgt_longform = u->msgtl_header.msgt_longform,
+      .msgt_deallocate = u->msgtl_header.msgt_deallocate,
+      .msgt_unused = 0
+    }
+  };
+  *k = kernel;
+}
+
+static inline void mach_msg_kernel_type_to_user(const mach_msg_type_t *k,
+    mach_msg_user_type_t *u) {
+  u->msgt_name = k->msgt_name;
+  u->msgt_size = k->msgt_size;
+  u->msgt_number = k->msgt_number;
+  u->msgt_inline = k->msgt_inline;
+  u->msgt_longform = k->msgt_longform;
+  u->msgt_deallocate = k->msgt_deallocate;
+  u->msgt_unused = 0;
+}
+
+static inline void mach_msg_kernel_type_to_user_long(const 
mach_msg_type_long_t *k,
+    mach_msg_user_type_long_t *u) {
+  const mach_msg_user_type_long_t user = {
+    .msgtl_header = {
+      .msgt_name = 0,
+      .msgt_size = 0,
+      .msgt_number = 0,
+      .msgt_inline = k->msgtl_header.msgt_inline,
+      .msgt_longform = k->msgtl_header.msgt_longform,
+      .msgt_deallocate = k->msgtl_header.msgt_deallocate,
+      .msgt_unused = 0
+    },
+    .msgtl_name = k->msgtl_header.msgt_name,
+    .msgtl_size = k->msgtl_header.msgt_size,
+    .msgtl_number = k->msgtl_header.msgt_number
+  };
+  *u = user;
+}
+#endif
+
 static inline int copyin_mach_msg_type(const rpc_vm_offset_t *uaddr, 
mach_msg_type_t *kaddr) {
 #ifdef USER32
-  int ret;
-  ret = copyin(uaddr, kaddr, sizeof(mach_msg_user_type_t));
-  kaddr->unused_msgtl_number = 0;
-  return ret;
+  mach_msg_user_type_t user;
+  int ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_t));
+  if (ret) {
+    return ret;
+  }
+  mach_msg_user_type_to_kernel(&user, kaddr);
+  return 0;
 #else
   return copyin(uaddr, kaddr, sizeof(mach_msg_type_t));
 #endif
@@ -100,7 +162,9 @@ static inline int copyin_mach_msg_type(const 
rpc_vm_offset_t *uaddr, mach_msg_ty
 
 static inline int copyout_mach_msg_type(const mach_msg_type_t *kaddr, 
rpc_vm_offset_t  *uaddr) {
 #ifdef USER32
-  return copyout(kaddr, uaddr, sizeof(mach_msg_user_type_t));
+  mach_msg_user_type_t user;
+  mach_msg_kernel_type_to_user(kaddr, &user);
+  return copyout(&user, uaddr, sizeof(mach_msg_user_type_t));
 #else
   return copyout(kaddr, uaddr, sizeof(mach_msg_type_t));
 #endif
@@ -109,15 +173,10 @@ static inline int copyout_mach_msg_type(const 
mach_msg_type_t *kaddr, rpc_vm_off
 static inline int copyin_mach_msg_type_long(const rpc_vm_offset_t *uaddr, 
mach_msg_type_long_t *kaddr) {
 #ifdef USER32
   mach_msg_user_type_long_t user;
-  int ret;
-  ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_long_t));
+  int ret = copyin(uaddr, &user, sizeof(mach_msg_user_type_long_t));
   if (ret)
     return ret;
-  /* The first 4 bytes are laid out in the same way. */
-  memcpy(&kaddr->msgtl_header, &user.msgtl_header, 
sizeof(mach_msg_user_type_t));
-  kaddr->msgtl_name = user.msgtl_name;
-  kaddr->msgtl_size = user.msgtl_size;
-  kaddr->msgtl_number = user.msgtl_number;
+  mach_msg_user_type_to_kernel_long(&user, kaddr);
   return 0;
 #else
   return copyin(uaddr, kaddr, sizeof(mach_msg_type_long_t));
@@ -127,10 +186,7 @@ static inline int copyin_mach_msg_type_long(const 
rpc_vm_offset_t *uaddr, mach_m
 static inline int copyout_mach_msg_type_long(const mach_msg_type_long_t 
*kaddr, rpc_vm_offset_t *uaddr) {
 #ifdef USER32
   mach_msg_user_type_long_t user;
-  memcpy(&user.msgtl_header, &kaddr->msgtl_header, 
sizeof(mach_msg_user_type_t));
-  user.msgtl_name = kaddr->msgtl_name;
-  user.msgtl_size = kaddr->msgtl_size;
-  user.msgtl_number = kaddr->msgtl_number;
+  mach_msg_kernel_type_to_user_long(kaddr, &user);
   return copyout(&user, uaddr, sizeof(mach_msg_user_type_long_t));
 #else
   return copyout(kaddr, uaddr, sizeof(mach_msg_type_long_t));
-- 
2.39.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]