Re: Come watch a live stream coding session for the Hurd Video

2024-06-02 Thread Sergey Bugaev
On Sun, Jun 2, 2024 at 12:22 AM Joshua Branson  wrote:
> So we had an awesome time today watching Sergey code a trivial translator (1) 
> and do
> some glibc hacking (2).  Sergey coded and chatted for 4 and 1/2 hours!  Three 
> cheers
> for that kind of commitment!  Thanks pal!
>
> In the livestream today, Sergey wrote caesar.c, which implements a simple 
> caeser
> cipher. It's a toy. A caesar cipher is EASY to break, but it was fun watching
> him code it out!

Hi all,

thanks for attending, and thanks Joshua for organizing it!

Let's do this again sometime? -- hopefully with less technical issues
related to recording/audio/video. I've got plenty of exciting ideas of
things to do. There are projects I started but haven't completed, like
the new bootstrap process (that Josh keeps calling "serverboot v2") or
the new in-tree, Hurd-native libfuse (which is an full translator
framework in its own right, a peer to libdiskfs/libnetfs/libtrivfs,
but mostly API-compatible with the Linux libfuse), or epoll/Wayland
(which is mostly complete, but it needs to be updated / cleaned up,
and published). Or, we could get started on writing that shiny new
translator framework in Rust :)

We ended the stream on a somewhat of a cliffhanger: can we run
caesarfs (see, Joshua misspelled it too, so it's not just me!) on the
aarch64-gnu system? The process was getting created, but then it
crashed before it got a chance to handshake with its parent translator
(root ext2fs), and thus fake-console-run.c was getting EDIED trying to
open the file. Turns out, we need to explicitly null-terminate the
last argv entry too when setting a static translator record from my
GNU/Linux host, so instead of
$ sudo setfattr -n gnu.translator -v
'/hurd/caesar\000/libexec/hello-world.txt'
/mnt/libexec/hello-world.txt.csr
I should have done
$ sudo setfattr -n gnu.translator -v
'/hurd/caesar\000/libexec/hello-world.txt\000'
/mnt/libexec/hello-world.txt.csr

It was crashing inside ld-arrach64.so.1 trying to parse its argv,
since it expected them to be in the argz format, so null-terminated.
(Did I mention how incredibly useful being able to backtrace through
syscall/fault/interrupt boundaries is for debugging?)

With that fixed (no changes to the translator itself, but the
translator record changed as shown above), I do get:

GNU Mach 1.8
Kernel command line: foo=bar
Booting in EL1
vm_page: page table size: 262144 entries (20480k)
vm_page: DMA: pages: 262144 (1024M), free: 221873 (866M)
vm_page: DMA: min:13107 low:15728 high:26214
Model name: linux dummy-virt
module 0: rootfs $(rootfs-device=ramdisk-create)
rd0: 36700160 bytes @83424000
module 1: ld-aarch64.so.1 /hurd/exec $(exec-task=task-create)
module 2: ext2fs --host-priv-port=${host-port}
--device-master-port=${device-port} --exec-server-task=${exec-task}
--multiboot-command-line=${kernel-command-line} -T device
${rootfs-device} $(task-create) $(task-resume)
3 bootstrap modules
task loaded: ld-aarch64.so.1 /hurd/exec
task loaded: ext2fs --host-priv-port=1 --device-master-port=2
--exec-server-task=3 --multiboot-command-line=foo=bar -T device rd0

start ext2fs: Hello world!
fread () -> 5
Uryyb

"Uryyb" is of course "Hello" with ROT13 applied :) So we were very close.

Sergey



Re: Come watch a live stream coding session for the Hurd

2024-05-31 Thread Sergey Bugaev
Hi,

On Fri, May 31, 2024 at 3:18 PM Almudena Garcia
 wrote:
> Other idea could be a magnet/torrent translator
>
> wget magnet:?fl=http://...
>
> and downloading the torrent file without a torrent client

bittorrentfs would be cool indeed, and it's something that I wanted to
write for a long time actually. It'd accept either magnet links as you
suggest, or a .torrent file (possibly itself located on an httpfs
mount...). But: that'd be a large project, and definitely not
something I would write over an hour on a livestream. Also that'd be
netfs, not trivfs, since a BitTorrent share can contain a file tree,
much like an archive.

We're going to do something much more simple that could serve as an
introduction to trivfs and Hurd server programming in general.
Specifically, I'm thinking we'd make a translator that takes an
existing file and wraps reads/writes with Caesar's cipher / ROT13.
That's something that Josh has mentioned he wanted to write in the
past [0]; and also recently he recorded himself having a hard time
trying to understand how to make a trivfs-based translator [1], so I
thought it would make sense to help him (and anyone else who'd be
interested) understand that.

[0]: https://marc.info/?l=hurd-bug=162142791926428=2
[1]: https://video.hardlimit.com/w/cd6bf857-5d54-47a3-9112-9ab786b13bac

Sergey



Re: [PATCH 9/9] Add a test for thread state

2024-04-16 Thread Sergey Bugaev
On Tue, Apr 16, 2024 at 4:01 AM Samuel Thibault  wrote:
> Ah, no, I mis read the result. It does stay stuck on x86_64.

Indeed, thanks. Reproduced and fixed; I was accidentally using rsp
(instead of ursp) in one place.

Sergey

-- >8 --

This tests generating and handling exceptions, thread_get_state(),
thread_set_state(), and newly added thread_set_self_state().  It does
many of the same things that glibc does when handling a signal.
---
 tests/test-thread-state.c | 215 ++
 tests/user-qemu.mk|   3 +-
 2 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 tests/test-thread-state.c

diff --git a/tests/test-thread-state.c b/tests/test-thread-state.c
new file mode 100644
index ..b78ab110
--- /dev/null
+++ b/tests/test-thread-state.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#if defined(__x86_64__) || defined(__i386__)
+#define THREAD_STATE_FLAVORi386_THREAD_STATE
+#define THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
+#elif defined(__aarch64__)
+#define THREAD_STATE_FLAVORAARCH64_THREAD_STATE
+#define THREAD_STATE_COUNT AARCH64_THREAD_STATE_COUNT
+#else
+#error "Don't know which state to use on this platform"
+#endif
+
+/*
+ * We'll make the thread itself run this function when it faults.
+ * This simulates handling a Unix SIGSEGV.
+ */
+static void __attribute__((noreturn)) fault_handler(
+   vm_offset_t fault_address,
+   thread_state_t  state)
+{
+   kern_return_t   kr;
+   vm_size_t   i;
+   vm_offset_t addr = fault_address;
+
+   printf("Handling a fault at 0x%p\n", fault_address);
+
+   /*
+*  Allocate the missing area of memory.
+*/
+   kr = vm_allocate(mach_task_self(), , vm_page_size, FALSE);
+   ASSERT_RET(kr, "failed to allocate missing memory");
+
+   /*
+*  Fill it with some data.
+*/
+   for (i = 0; i < vm_page_size / sizeof(int); i++)
+   *((int *) addr + i) = i;
+
+   /*
+*  Return back to the interrupted code.
+*/
+   kr = thread_set_self_state(THREAD_STATE_FLAVOR, state,
+  THREAD_STATE_COUNT);
+   ASSERT_RET(kr, "thread_set_self_state failed");
+   FAILURE("thread_set_self_state returned");
+}
+
+/*
+ * The exception_raise() RPC handler.  Mach calls this when the other 
thread faults.
+ * This runs in a different thread; it could fix things up directly and 
resume the
+ * thread.  Instead, it sets things up so that the thread itself will fix 
things
+ * for itself, and then return back to what it was doing.
+ */
+kern_return_t catch_exception_raise(
+   mach_port_t exception_port,
+   thread_tthread,
+   task_t  task,
+   integer_t   exception,
+   integer_t   code,
+   long_integer_t  subcode)
+{
+   kern_return_t   kr;
+   vm_offset_t off;
+#if defined(__x86_64__) || defined(__i386__)
+   struct i386_thread_statestate;
+#elif defined(__aarch64__)
+   struct aarch64_thread_state state;
+#else
+#error "Don't know which state to use on this platform"
+#endif
+   mach_msg_type_number_t  state_count = THREAD_STATE_COUNT;
+
+
+   printf("Received exception_raise(%u %u 0x%lx)\n", exception, code, 
subcode);
+
+   /*
+*  We only want to handle EXC_BAD_ACCESS/KERN_INVALID_ADDRESS.
+*  Return an error to proceed with the default handling otherwise.
+*/
+   if (exception != EXC_BAD_ACCESS)
+   return KERN_FAILURE;
+   if (code != KERN_INVALID_ADDRESS)
+   return KERN_FAILURE;
+
+   kr = thread_get_state(thread, THREAD_STATE_FLAVOR,
+ (thread_state_t) , _count);
+   ASSERT_RET(kr, "thread_get_state get failed");
+   ASSERT(state_count == THREAD_STATE_COUNT, "bad state_count");
+
+#if defined(__x86_64__)
+   /*
+*  Place a copy of the state on the thread's stack.
+*/
+   off = ((state.ursp - 128 - sizeof(state)) & ~15UL) - 8;
+   memcpy((void *) 

Re: [RFC PATCH 03/23] Allow glibc to be compiled without EXEC_PAGESIZE

2024-04-15 Thread Sergey Bugaev
Hello,

On Wed, Apr 10, 2024 at 2:57 PM Florian Weimer  wrote:
> * Sergey Bugaev:
>
> > We could define EXEC_PAGESIZE to some conservative value on
> > aarch64-gnu too, if it turns out that this little workaround is really
> > required. But it seems cleaner to make sure we don't need to, as
> > Roland's email suggests, and introducing a new port that doesn't have
> > a fixed page size (and doesn't come with an EXEC_PAGESIZE value
> > already defined in kernel headers) seems to be a good opportunity to
> > do that. That's my reasoning here.
>
> But the ELF image must be laid out with certain expectations regarding
> the maximum support page size.  Otherwise, something (kernel or dynamic
> linker) needs to perform copies or upgrade conflicting permissions
> within one page to a superset of all permissions.  I don't think we have
> code for that today, and we wouldn't necessarily want to implement that,
> I think.

Certainly -- and I wouldn't expect the kernel or the dynamic linker to
do anything about it other than reporting an error.

I think what you're saying is you consider EXEC_PAGESIZE to indeed
describe/define this required alignment of ELF segments (as the name
suggests). If I adopt that view, then yes, having EXEC_PAGESIZE makes
sense, and it makes some sense to use it as a conservative page size
value to use while the real value is not yet available (assuming there
is a real need for that).

The way I've been viewing it -- based on the fact that neither Linux's
nor glibc's (dynamic) nor BFD's nor LLVM's (static) linkers use it for
that purpose -- is that it's just some PAGE_SIZE-like definition
that's unrelated to binary loading (despite its name -- perhaps it has
been historically related to segment alignment in some old versions of
Linux?) that has been co-opted by glibc for pre-initializing
dl_pagesize, for dubious reasons. It also seems to be a Linux- (and
x86 Hurd) specific thing; I cannot find it in the BSDs.

Which one is it?

Sergey



[PATCH 9/9] Add a test for thread state

2024-04-15 Thread Sergey Bugaev
This tests generating and handling exceptions, thread_get_state(),
thread_set_state(), and newly added thread_set_self_state().  It does
many of the same things that glibc does when handling a signal.
---
Note that I only tested this on i386 and AArch64, not on x86_64.

 tests/test-thread-state.c | 215 ++
 tests/user-qemu.mk|   3 +-
 2 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 tests/test-thread-state.c

diff --git a/tests/test-thread-state.c b/tests/test-thread-state.c
new file mode 100644
index ..1330587a
--- /dev/null
+++ b/tests/test-thread-state.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#if defined(__x86_64__) || defined(__i386__)
+#define THREAD_STATE_FLAVORi386_THREAD_STATE
+#define THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
+#elif defined(__aarch64__)
+#define THREAD_STATE_FLAVORAARCH64_THREAD_STATE
+#define THREAD_STATE_COUNT AARCH64_THREAD_STATE_COUNT
+#else
+#error "Don't know which state to use on this platform"
+#endif
+
+/*
+ * We'll make the thread itself run this function when it faults.
+ * This simulates handling a Unix SIGSEGV.
+ */
+static void __attribute__((noreturn)) fault_handler(
+   vm_offset_t fault_address,
+   thread_state_t  state)
+{
+   kern_return_t   kr;
+   vm_size_t   i;
+   vm_offset_t addr = fault_address;
+
+   printf("Handling a fault at 0x%p\n", fault_address);
+
+   /*
+*  Allocate the missing area of memory.
+*/
+   kr = vm_allocate(mach_task_self(), , vm_page_size, FALSE);
+   ASSERT_RET(kr, "failed to allocate missing memory");
+
+   /*
+*  Fill it with some data.
+*/
+   for (i = 0; i < vm_page_size / sizeof(int); i++)
+   *((int *) addr + i) = i;
+
+   /*
+*  Return back to the interrupted code.
+*/
+   kr = thread_set_self_state(THREAD_STATE_FLAVOR, state,
+  THREAD_STATE_COUNT);
+   ASSERT_RET(kr, "thread_set_self_state failed");
+   FAILURE("thread_set_self_state returned");
+}
+
+/*
+ * The exception_raise() RPC handler.  Mach calls this when the other 
thread faults.
+ * This runs in a different thread; it could fix things up directly and 
resume the
+ * thread.  Instead, it sets things up so that the thread itself will fix 
things
+ * for itself, and then return back to what it was doing.
+ */
+kern_return_t catch_exception_raise(
+   mach_port_t exception_port,
+   thread_tthread,
+   task_t  task,
+   integer_t   exception,
+   integer_t   code,
+   long_integer_t  subcode)
+{
+   kern_return_t   kr;
+   vm_offset_t off;
+#if defined(__x86_64__) || defined(__i386__)
+   struct i386_thread_statestate;
+#elif defined(__aarch64__)
+   struct aarch64_thread_state state;
+#else
+#error "Don't know which state to use on this platform"
+#endif
+   mach_msg_type_number_t  state_count = THREAD_STATE_COUNT;
+
+
+   printf("Received exception_raise(%u %u 0x%lx)\n", exception, code, 
subcode);
+
+   /*
+*  We only want to handle EXC_BAD_ACCESS/KERN_INVALID_ADDRESS.
+*  Return an error to proceed with the default handling otherwise.
+*/
+   if (exception != EXC_BAD_ACCESS)
+   return KERN_FAILURE;
+   if (code != KERN_INVALID_ADDRESS)
+   return KERN_FAILURE;
+
+   kr = thread_get_state(thread, THREAD_STATE_FLAVOR,
+ (thread_state_t) , _count);
+   ASSERT_RET(kr, "thread_get_state get failed");
+   ASSERT(state_count == THREAD_STATE_COUNT, "bad state_count");
+
+#if defined(__x86_64__)
+   /*
+*  Place a copy of the state on the thread's stack.
+*/
+   off = ((state.rsp - 128 - sizeof(state)) & ~15UL) - 8;
+   memcpy((void *) off, , sizeof(state));
+
+   /*
+*  Make it call fault_handler(subcode, off).
+*/
+   state.ursp = off;
+   state.rip = (vm_offset_t) 

[PATCH 3/9] aarch64: Add public syscall ABI

2024-04-15 Thread Sergey Bugaev
We use largely the same ABI as Linux: a syscall is invoked with the
"svc #0" instruction, passing arguments the same way as for a regular
function call.  Specifically, up to 8 arguments are passed in the x0-x7
registers, and the rest are placed on the stack (this is only necessary
for the vm_map() syscall).  w8 should contain the (negative) Mach trap
number.  A syscall preserves all registers except for x0, which upon
returning contains the return value.
---
 aarch64/Makefrag.am   |  2 ++
 aarch64/include/mach/aarch64/asm.h| 39 +++
 aarch64/include/mach/aarch64/syscall_sw.h | 32 +++
 3 files changed, 73 insertions(+)
 create mode 100644 aarch64/include/mach/aarch64/asm.h
 create mode 100644 aarch64/include/mach/aarch64/syscall_sw.h

diff --git a/aarch64/Makefrag.am b/aarch64/Makefrag.am
index 15ce3f49..7949d7ba 100644
--- a/aarch64/Makefrag.am
+++ b/aarch64/Makefrag.am
@@ -27,9 +27,11 @@ if HOST_aarch64
 
 include_mach_aarch64dir = $(includedir)/mach/aarch64
 include_mach_aarch64_HEADERS = \
+   aarch64/include/mach/aarch64/asm.h \
aarch64/include/mach/aarch64/boolean.h \
aarch64/include/mach/aarch64/kern_return.h \
aarch64/include/mach/aarch64/machine_types.defs \
+   aarch64/include/mach/aarch64/syscall_sw.h \
aarch64/include/mach/aarch64/vm_types.h
 
 endif # HOST_aarch64
diff --git a/aarch64/include/mach/aarch64/asm.h 
b/aarch64/include/mach/aarch64/asm.h
new file mode 100644
index ..ae94e637
--- /dev/null
+++ b/aarch64/include/mach/aarch64/asm.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MACH_AARCH64_ASM_H_
+#define _MACH_AARCH64_ASM_H_
+
+#define EXT(x) x
+#define LEXT(x)x ## :
+#define SEXT(x)#x
+
+#define TEXT_ALIGN 4
+#define DATA_ALIGN 4
+
+#define SVCsvc # (0)
+#define ENTRY(x)   .globl EXT(x); .type EXT(x), @function; .p2align 
TEXT_ALIGN; LEXT(x)
+#define END(x) .size x,.-x
+
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#define MACH_BTI_C bti c
+#else
+#define MACH_BTI_C
+#endif
+
+#endif /* _MACH_AARCH64_ASM_H_ */
diff --git a/aarch64/include/mach/aarch64/syscall_sw.h 
b/aarch64/include/mach/aarch64/syscall_sw.h
new file mode 100644
index ..cf13dd7e
--- /dev/null
+++ b/aarch64/include/mach/aarch64/syscall_sw.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef_MACH_AARCH64_SYSCALL_SW_H_
+#define _MACH_AARCH64_SYSCALL_SW_H_
+
+#include 
+
+#define kernel_trap(trap_name,trap_number,number_args)  \
+ENTRY(trap_name)  \
+   MACH_BTI_C; \
+   mov w8, #(trap_number);  \
+   SVC;  \
+   ret;  \
+END(trap_name)
+
+#endif /* _MACH_AARCH64_SYSCALL_SW_H_ */
-- 
2.44.0




[PATCH 5/9] aarch64: Add mach_aarch64 API

2024-04-15 Thread Sergey Bugaev
This currently contains a single RPC to get Linux-compatible hwcaps,
as well as the values of MIDR_EL1 and REVIDR_EL1 system registers.

In the future, this is expected to host the APIs to manage PAC keys,
and possibly some sort of AArch64-specific APIs for userland IRQ
handlers.
---
 aarch64/Makefrag.am   |   3 +
 aarch64/aarch64/mach_aarch64.srv  |  23 
 .../include/mach/aarch64/mach_aarch64.defs|  52 
 .../include/mach/aarch64/mach_aarch64_types.h | 118 ++
 4 files changed, 196 insertions(+)
 create mode 100644 aarch64/aarch64/mach_aarch64.srv
 create mode 100644 aarch64/include/mach/aarch64/mach_aarch64.defs
 create mode 100644 aarch64/include/mach/aarch64/mach_aarch64_types.h

diff --git a/aarch64/Makefrag.am b/aarch64/Makefrag.am
index 3da88c18..ff7bcefb 100644
--- a/aarch64/Makefrag.am
+++ b/aarch64/Makefrag.am
@@ -17,6 +17,7 @@
 # Building a distribution.
 #
 EXTRA_DIST += \
+   aarch64/aarch64/mach_aarch64.srv \
aarch64/include/mach/aarch64
 
 if HOST_aarch64
@@ -30,6 +31,8 @@ include_mach_aarch64_HEADERS = \
aarch64/include/mach/aarch64/asm.h \
aarch64/include/mach/aarch64/boolean.h \
aarch64/include/mach/aarch64/kern_return.h \
+   aarch64/include/mach/aarch64/mach_aarch64.defs \
+   aarch64/include/mach/aarch64/mach_aarch64_types.h \
aarch64/include/mach/aarch64/machine_types.defs \
aarch64/include/mach/aarch64/syscall_sw.h \
aarch64/include/mach/aarch64/vm_param.h \
diff --git a/aarch64/aarch64/mach_aarch64.srv b/aarch64/aarch64/mach_aarch64.srv
new file mode 100644
index ..7dd8f9e9
--- /dev/null
+++ b/aarch64/aarch64/mach_aarch64.srv
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* This is a server presentation file.  */
+
+#define KERNEL_SERVER 1
+
+#include 
diff --git a/aarch64/include/mach/aarch64/mach_aarch64.defs 
b/aarch64/include/mach/aarch64/mach_aarch64.defs
new file mode 100644
index ..0fe1eb62
--- /dev/null
+++ b/aarch64/include/mach/aarch64/mach_aarch64.defs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * Special functions for aarch64.
+ */
+
+subsystem
+#ifKERNEL_SERVER
+ KernelServer
+#endif /* KERNEL_SERVER */
+  mach_aarch64 4500;
+
+#include 
+#include 
+
+#ifdef MACH_AARCH64_IMPORTS
+MACH_AARCH64_IMPORTS
+#endif
+
+import ;
+
+/*
+ * An array containing bitmasks; the meaning of individual
+ * bits is defined by the HWCAP_* and HWCAP2_* constants
+ * from the mach_aarch64_types.h header. In this version
+ * of Mach, the array will contain two items, but future
+ * versions can add more items and more bits (HWCAP3_* and
+ * so forth).
+ */
+type   hwcaps_t=   array[*:16] of uint32_t;
+
+routine aarch64_get_hwcaps(
+   host: host_t;
+   out hwcaps  : hwcaps_t, CountInOut;
+   out midr_el1: uint64_t;
+   out revidr_el1  : uint64_t);
diff --git a/aarch64/include/mach/aarch64/mach_aarch64_types.h 
b/aarch64/include/mach/aarch64/mach_aarch64_types.h
new file mode 100644
index ..98fd6c4b
--- /dev/null
+++ b/aarch64/include/mach/aarch64/mach_aarch64_types.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as 

[PATCH 6/9] aarch64: Add exception type definitions

2024-04-15 Thread Sergey Bugaev
A few yet-unimplemented codes are also sketched out; these are included
so you know roughly what to expect once the missing functionality gets
implemented, but are not in any way stable or usable.
---
 aarch64/Makefrag.am  |  1 +
 aarch64/include/mach/aarch64/exception.h | 90 
 2 files changed, 91 insertions(+)
 create mode 100644 aarch64/include/mach/aarch64/exception.h

diff --git a/aarch64/Makefrag.am b/aarch64/Makefrag.am
index ff7bcefb..13c9439a 100644
--- a/aarch64/Makefrag.am
+++ b/aarch64/Makefrag.am
@@ -30,6 +30,7 @@ include_mach_aarch64dir = $(includedir)/mach/aarch64
 include_mach_aarch64_HEADERS = \
aarch64/include/mach/aarch64/asm.h \
aarch64/include/mach/aarch64/boolean.h \
+   aarch64/include/mach/aarch64/exception.h \
aarch64/include/mach/aarch64/kern_return.h \
aarch64/include/mach/aarch64/mach_aarch64.defs \
aarch64/include/mach/aarch64/mach_aarch64_types.h \
diff --git a/aarch64/include/mach/aarch64/exception.h 
b/aarch64/include/mach/aarch64/exception.h
new file mode 100644
index ..2e96e09a
--- /dev/null
+++ b/aarch64/include/mach/aarch64/exception.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * Codes and subcodes for AArch64 exceptions.
+ */
+#ifndef_MACH_AARCH64_EXCEPTION_H_
+#define _MACH_AARCH64_EXCEPTION_H_
+
+
+/*
+ * EXC_BAD_INSTRUCTION
+ */
+
+#define EXC_AARCH64_UNK1   /* unknown reason 
(unallocated instruction) */
+#define EXC_AARCH64_IL 2   /* illegal execution state 
(PSTATE.IL set) */
+
+/*
+ * EXC_ARITHMETIC
+ */
+
+#define EXC_AARCH64_IDF1   /* floating-point input 
denormal */
+#define EXC_AARCH64_IXF2   /* floating-point 
inexact */
+#define EXC_AARCH64_UFF3   /* floating-point 
underflow */
+#define EXC_AARCH64_OFF4   /* floating-point 
overflow */
+#define EXC_AARCH64_DZF5   /* floating-point 
divide by zero */
+#define EXC_AARCH64_IOF6   /* floating-point 
invalid operation */
+
+/*
+ * EXC_SOFTWARE
+ */
+
+#define EXC_AARCH64_SVC1   /* SVC that's not a 
valid syscall, subcode contains immediate */
+
+/*
+Not yet:
+#define EXC_AARCH64_HVC2   HVC, subcode contains 
immediate
+#define EXC_AARCH64_SMC3   SMC, subcode contains 
immediate
+*/
+
+/*
+ * EXC_BAD_ACCESS
+ *
+ * Exception code normally holds a kern_return_t value (such as
+ * KERN_INVALID_ADDRESS), but for AArch64-specific exceptions these
+ * values can be used as exception code instead; they must not conflict
+ * with kern_return_t values.
+ */
+
+#define EXC_AARCH64_AL 100 /* alignment fault */
+#define EXC_AARCH64_AL_PC  101 /* misaligned pc */
+#define EXC_AARCH64_AL_SP  102 /* misaligned sp */
+#define EXC_AARCH64_PAC103 /* PAC failure, subcode 
describes the key */
+#define EXC_AARCH64_BTI104 /* BTI failure, subcode 
contains BTYPE */
+
+/*
+Not yet:
+#define EXC_AARCH64_MTE105 MTE failure
+*/
+
+/*
+ * EXC_BREAKPOINT
+ */
+
+#define EXC_AARCH64_BRK1   /* BRK instruction, 
subcode contains immediate */
+#define EXC_AARCH64_SS 2   /* software single step, 
subcode contains EX flag, or -1 if unknown */
+#define EXC_AARCH64_BREAKPT3   /* hardware breakpoint */
+
+/*
+Not yet:
+#define EXC_AARCH64_WATCHPT_READ   4   hardware watchpoint (read), 
subcode contains accessed address
+#define EXC_AARCH64_WATCHPT_WRITE  5   hardware watchpoint (write), 
subcode contains accessed address
+*/
+
+#endif /* _MACH_AARCH64_EXCEPTION_H_ */
-- 
2.44.0




[PATCH 8/9] Add thread_set_self_state() trap

2024-04-15 Thread Sergey Bugaev
This is a new Mach trap that sets the calling thread's state to the
passed value, as if with a call to the thread_set_state() RPC.  If the
flavor of state being set is the one that contains the register used for
syscall return value (i386_THREAD_STATE or i386_REGS_SEGS_STATE on x86,
AARCH64_THREAD_STATE on AArch64), the set register value is *not*
overwritten with KERN_SUCCESS when the state gets set successfully, yet
errors do get reported if the syscall fails.

Although the trap is intended to enable userland to implement sigreturn
functionality in the AArch64 port (more on which below), the trap itself
is architecture-independent, and fully implemented in terms of the
existing kernel routines (thread_setstatus & thread_set_syscall_return).

This trap's functionality is similar to sigreturn() on Unix or
NtContinue() on NT.  The use case for these all is restoring the local
state of an interrupted thread in the following set-up:

1. A thread is running some arbitrary code.
2. An event happens that deserves the thread's immediate attention,
   analogous to a hardware interrupt request.  This might be caused by
   the thread itself (e.g. running into a Mach exception that was
   arranged to be handled by the same thread), or by external events
   (e.g. receiving a Unix SIGCHLD).
3. Another thread (or perhaps the kernel, although this is not the case
   on Mach) suspends the thread, saves its state at the point of
   interruption, alters its state to execute some sort of handler for
   the event, and resumes the thread again, now running the handler.
4. Once the thread is done running the handler, it wants to return to
   what it was doing at the time it was interrupted.  To do this, it
   needs to restore the state as saved at the moment of interruption.

Unlike with setjmp()/longjmp(), we cannot rely on the interrupted logic
collaborating in any way, as it's not aware that it's being interrupted.
This means that we have to fully restore the state, including values of
all the general-purpose registers, as well as the stack pointer, program
counter, and any state flags.

Depending on the instruction set, this may or may not be possible to do
fully in userland, simply by loading all the registers with their saved
values.  It should be more or less easy to load the saved values into
general-purpose registers, but state flags and the program counter can
be more of a challenge.  Loading the program counter value (in other
words, performing an indirect jump to the interrupted instruction) has
to be the very last thing we do, since we don't control the program flow
after that.  The only real place program counter can be loaded from is
popped off the stack, since all general-purpose registers would already
contain their restored values by that point, and using global storage is
incompatible with another interruption of the same kind happening at the
time we were about to return.  For the same reason, the saved program
counter cannot be really stored outside of the "active" stack area (such
as below the stack pointer), since otherwise it can get clobbered by
another interruption.

This means that to support fully-userland returns, the instruction set
must provide a single instruction that loads an address from the stack,
adjusts the stack pointer, and performs an indirect jump to the loaded
address.  The instruction must also either preserve (previously
restored) state flags, or additionally load state flags from the stack
in addition to the jump address.

On x86, 'ret' is such an instruction: it pops an address from the stack,
adjusting the stack pointer without modifying flags, and performs an
indirect jump to the address.  On x86_64, where the ABI mandates a red
zone, one can use the 'ret imm16' variant to additionally adjust the
stack pointer by the size of the red zone, atomically restoring the
value of the stack pointer at the time of the interruption while loading
the return address from outside the red zone.  This is how sigreturn is
implemented in glibc for the Hurd on x86.

On ARM AArch32, 'pop {pc}' (alternatively written 'ldr pc, [sp], #4') is
such an instruction: since SP and PC are just general-purpose, directly
accessible registers (r13 and r15), it is possible to perform a load
from the address pointed to by SP into PC, with a post-increment of SP.
It is, in fact, possible to restore all the other general-purpose
registers too in a single instruction this way: 'pop {r0-r12, r14, r15}'
will do that; here r13, the stack pointer, gets incremented after all
the other registers get loaded from the stack.  This also preserves the
CPSR flags, which would need to be restored just prior to the 'pop'.

On ARM AArch64 however, PC is no longer a directly accessible general-
purpose register (and SP is only accessible that way by some of the
instructions); so it is no longer possible to load PC from memory in a
single instruction.  The only way to perform an indirect jump is by
using one of the dedicated 

[PATCH 7/9] aarch64: Add thread state types

2024-04-15 Thread Sergey Bugaev
Notes:
* TPIDR_EL0, the TLS pointer, is included in the generic state directly.
* TPIDR2_EL0, part of the SME extension, is not included in the generic
  state.  If we add SME support, it will be a part of something like
  aarch64_sme_state.
* CPSR is not a real register in AArch64 (unlike in AArch32), but a
  collection of individually accessible bits and pieces from PSTATE.
  Due to how the kernel accesses user mode's PSTATE (via SPSR), it's
  convenient to represent PSTATE as a pseudo-register in the same
  format as SPSR.  This is also what QEMU and XNU do.
* There is no hardware-enforced 'natural' order to place the registers
  in, since no registers get pushed onto the stack on exception entry.
  Saving and restoring registers from an instance of struct
  aarch64_thread_state is implemented entirely in software, and the
  format is essentially arbitrary.
* aarch64_float_state includes registers of a 128-bit type; this may
  create issues for compilers other than GCC.
* fp_reserved is not a register, but a placeholder.  If and when Arm
  adds another floating-point meta-register, this will be changed to
  represent it, and that would not be considered a compatibility break,
  so don't access fp_reserved by name, or its value, from userland.
  Instead, memset the whole structure to 0 if starting from scratch, or
  memcpy an existing structure.

More thread state types could be added in the future, such as
aarch64_debug_state, aarch64_virt_state (for hardware-accelerated
virtualization), potentially ones for PAC, SVE/SME, etc.
---
 aarch64/Makefrag.am  |  1 +
 aarch64/include/mach/aarch64/thread_status.h | 43 
 2 files changed, 44 insertions(+)
 create mode 100644 aarch64/include/mach/aarch64/thread_status.h

diff --git a/aarch64/Makefrag.am b/aarch64/Makefrag.am
index 13c9439a..dd1837d4 100644
--- a/aarch64/Makefrag.am
+++ b/aarch64/Makefrag.am
@@ -36,6 +36,7 @@ include_mach_aarch64_HEADERS = \
aarch64/include/mach/aarch64/mach_aarch64_types.h \
aarch64/include/mach/aarch64/machine_types.defs \
aarch64/include/mach/aarch64/syscall_sw.h \
+   aarch64/include/mach/aarch64/thread_status.h \
aarch64/include/mach/aarch64/vm_param.h \
aarch64/include/mach/aarch64/vm_types.h
 
diff --git a/aarch64/include/mach/aarch64/thread_status.h 
b/aarch64/include/mach/aarch64/thread_status.h
new file mode 100644
index ..c0c7773e
--- /dev/null
+++ b/aarch64/include/mach/aarch64/thread_status.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef_MACH_AARCH64_THREAD_STATUS_H_
+#define _MACH_AARCH64_THREAD_STATUS_H_
+
+#define AARCH64_THREAD_STATE   1
+#define AARCH64_FLOAT_STATE2
+
+struct aarch64_thread_state {
+   uint64_t x[31];
+   uint64_t sp;
+   uint64_t pc;
+   uint64_t tpidr_el0;
+   uint64_t cpsr;  /* in SPSR format */
+};
+#define AARCH64_THREAD_STATE_COUNT (sizeof(struct aarch64_thread_state) / 
sizeof(unsigned int))
+
+struct aarch64_float_state {
+   __int128 v[32];
+   uint64_t fpsr;
+   uint64_t fpcr;
+   uint64_t fpmr;
+   uint64_t fp_reserved;   /* for when ARM adds another FP 
register */
+};
+#define AARCH64_FLOAT_STATE_COUNT  (sizeof(struct aarch64_float_state) / 
sizeof(unsigned int))
+
+#endif /* _MACH_AARHC64_THREAD_STATUS_H_ */
-- 
2.44.0




[PATCH 2/9] aarch64: Add the basics

2024-04-15 Thread Sergey Bugaev
This adds "aarch64" host support to the build system, along with some
uninteresting installed headers. The empty aarch64/aarch64/ast.h header
is also added to create the aarch64/aarch64/ directory (due to Git
peculiarity).

With this, it should be possible to run 'configure --host=aarch64-gnu'
and 'make install-data' successfully.
---
 Makefrag.am   |   3 +
 aarch64/Makefrag.am   |  35 +
 aarch64/aarch64/ast.h |  19 +++
 aarch64/configfrag.ac |  31 
 aarch64/include/mach/aarch64/boolean.h|  24 +++
 aarch64/include/mach/aarch64/kern_return.h|  25 +++
 .../include/mach/aarch64/machine_types.defs   | 102 
 aarch64/include/mach/aarch64/vm_types.h   | 147 ++
 configure.ac  |   5 +
 9 files changed, 391 insertions(+)
 create mode 100644 aarch64/Makefrag.am
 create mode 100644 aarch64/aarch64/ast.h
 create mode 100644 aarch64/configfrag.ac
 create mode 100644 aarch64/include/mach/aarch64/boolean.h
 create mode 100644 aarch64/include/mach/aarch64/kern_return.h
 create mode 100644 aarch64/include/mach/aarch64/machine_types.defs
 create mode 100644 aarch64/include/mach/aarch64/vm_types.h

diff --git a/Makefrag.am b/Makefrag.am
index 1674317e..2cc75bcf 100644
--- a/Makefrag.am
+++ b/Makefrag.am
@@ -611,3 +611,6 @@ include i386/Makefrag.am
 
 # x86_64.
 include x86_64/Makefrag.am
+
+# aarch64.
+include aarch64/Makefrag.am
diff --git a/aarch64/Makefrag.am b/aarch64/Makefrag.am
new file mode 100644
index ..15ce3f49
--- /dev/null
+++ b/aarch64/Makefrag.am
@@ -0,0 +1,35 @@
+# Makefile fragment for aarch64.
+
+# Copyright (C) 2023-2024 Free Software Foundation, Inc.
+
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+# "AS IS" CONDITION.  THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
+# LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
+# USE OF THIS SOFTWARE.
+
+#
+# Building a distribution.
+#
+EXTRA_DIST += \
+   aarch64/include/mach/aarch64
+
+if HOST_aarch64
+
+#
+# Installation.
+#
+
+include_mach_aarch64dir = $(includedir)/mach/aarch64
+include_mach_aarch64_HEADERS = \
+   aarch64/include/mach/aarch64/boolean.h \
+   aarch64/include/mach/aarch64/kern_return.h \
+   aarch64/include/mach/aarch64/machine_types.defs \
+   aarch64/include/mach/aarch64/vm_types.h
+
+endif # HOST_aarch64
diff --git a/aarch64/aarch64/ast.h b/aarch64/aarch64/ast.h
new file mode 100644
index ..91e5c568
--- /dev/null
+++ b/aarch64/aarch64/ast.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Nothing here.  */
diff --git a/aarch64/configfrag.ac b/aarch64/configfrag.ac
new file mode 100644
index ..03f980bf
--- /dev/null
+++ b/aarch64/configfrag.ac
@@ -0,0 +1,31 @@
+dnl Configure fragment for aarch64.
+
+dnl Copyright (C) 2024 Free Software Foundation, Inc.
+
+dnl Permission to use, copy, modify and distribute this software and its
+dnl documentation is hereby granted, provided that both the copyright
+dnl notice and this permission notice appear in all copies of the
+dnl software, derivative works or modified versions, and any portions
+dnl thereof, and that both notices appear in supporting documentation.
+dnl
+dnl THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+dnl "AS IS" CONDITION.  THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
+dnl LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
+dnl USE OF THIS SOFTWARE.
+
+[case $host_cpu in
+  aarch64)]
+AM_CONDITIONAL([HOST_aarch64], [true])
+
+[
+# Does the architecture provide machine-specific interfaces?
+mach_machine_routines=1
+;;
+  *)]
+AM_CONDITIONAL([HOST_aarch64], [false])
+[;;
+esac]
+
+dnl Local Variables:
+dnl mode: autoconf
+dnl End:
diff --git 

[PATCH 0/9] AArch64 Mach public headers

2024-04-15 Thread Sergey Bugaev
Hello!

This patchset contains public headers for AArch64 support in GNU Mach,
along with just enough buildsystem infrastructure to recognize and
install them. It is quite similar to the "sketch" patches that I have
posted in January of this year, but I have done a number of changes for
two reasons. One reason is me becoming a lot more familiar with ARM and
AArch64, in particular having done a bunch of reading of the Arm ARM.

The other reason is there is now a real port of GNU Mach to AArch64,
using these headers as its actual API/ABI. We got the Mach port to run
glibc, several Hurd servers, and simple Unix programs, including things
like fork/exec and signal delivery & handling working, which excersizes
these architecture-specific definitions (thread state & exceptions). We
have also managed to do some testing on real hardware; although not
everything is working yet, we have seen thread state manipulation &
Mach handling an unaligned SP fault work as expected.

While the Mach port exists, I'm not proposing we merge it yet. This
patch set only contains the headers, pulled from the AArch64 port
branch. It is small enough, already in ready-to-be-merged state (as
opposed to prototype/sketch state it was this January), and should be
easy to review. At the same time, this should be enough to build glibc
and most of the Hurd, and then the rest of the userland; this also means
that merging this patchset should be enough to unblock merging the glibc
port upstream, now that the GCC patches are in.

Sergey



[PATCH 4/9] aarch64: Add vm_param.h

2024-04-15 Thread Sergey Bugaev
And make it so that the generic vm_param.h doesn't require the machine-
specific one to define PAGE_SIZE etc.  We *don't* want a PAGE_SIZE
constant to be statically exported to userland; instead userland should
initialize vm_page_size by querying vm_statistics(), and then use
vm_page_size.

We'd also like to eventually avoid exporting VM_MAX_ADDRESS, but this is
not feasible at the moment.  To make it feasible in the future, userland
should try to avoid relying on the definition where possible.
---
 aarch64/Makefrag.am |  1 +
 aarch64/include/mach/aarch64/vm_param.h | 34 +
 include/mach/vm_param.h |  6 ++---
 3 files changed, 38 insertions(+), 3 deletions(-)
 create mode 100644 aarch64/include/mach/aarch64/vm_param.h

diff --git a/aarch64/Makefrag.am b/aarch64/Makefrag.am
index 7949d7ba..3da88c18 100644
--- a/aarch64/Makefrag.am
+++ b/aarch64/Makefrag.am
@@ -32,6 +32,7 @@ include_mach_aarch64_HEADERS = \
aarch64/include/mach/aarch64/kern_return.h \
aarch64/include/mach/aarch64/machine_types.defs \
aarch64/include/mach/aarch64/syscall_sw.h \
+   aarch64/include/mach/aarch64/vm_param.h \
aarch64/include/mach/aarch64/vm_types.h
 
 endif # HOST_aarch64
diff --git a/aarch64/include/mach/aarch64/vm_param.h 
b/aarch64/include/mach/aarch64/vm_param.h
new file mode 100644
index ..d7b1e281
--- /dev/null
+++ b/aarch64/include/mach/aarch64/vm_param.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023-2024 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef_MACH_AARCH64_VM_PARAM_H_
+#define _MACH_AARCH64_VM_PARAM_H_
+
+#include 
+
+#define BYTE_SIZE  8   /* byte size in bits */
+
+/*
+ * TODO: Exporting VM_MAX_ADDRESS basically locks in
+ * VM_AARCH64_T0SZ being 48.  Consider dropping it from this
+ * public header once userland no longer depends on it.
+ */
+#define VM_MIN_ADDRESS (0ULL)
+#define VM_MAX_ADDRESS (0x1ULL)
+
+#endif /* _MACH_AARCH64_VM_PARAM_H_ */
diff --git a/include/mach/vm_param.h b/include/mach/vm_param.h
index 4cbd0eca..8ddb5d99 100644
--- a/include/mach/vm_param.h
+++ b/include/mach/vm_param.h
@@ -59,9 +59,7 @@
  * PAGE_SIZE and PAGE_MASK should also be variables
  * so their values don't have to be constantly recomputed.)
  */
-#ifndef PAGE_SHIFT
-#error mach/machine/vm_param.h needs to define PAGE_SHIFT.
-#endif
+#ifdef PAGE_SHIFT
 
 #ifndef PAGE_SIZE
 #define PAGE_SIZE (1 << PAGE_SHIFT)
@@ -99,4 +97,6 @@
 #definepage_aligned(x) vm_offset_t) (x)) & PAGE_MASK) == 0)
 #definephys_aligned(x) phys_addr_t) (x)) & PAGE_MASK) == 0)
 
+#endif /* PAGE_SHIFT */
+
 #endif /* _MACH_VM_PARAM_H_ */
-- 
2.44.0




[PATCH 1/9] Add CPU_TYPE_ARM64

2024-04-15 Thread Sergey Bugaev
This is distinct from CPU_TYPE_ARM, since we're going to exclusively use
AArch64 / A64, which CPU_TYPE_ARM was never meant to support, and to
match EM_AARCH64, which is also separate from EM_ARM.  CPU_TYPE_X86_64
was similarly made distinct from CPU_TYPE_I386.

This is named CPU_TYPE_ARM64 rather than CPU_TYPE_AARCH64, since AArch64
is an "execution state" (analogous to long mode on x86_64) rather than a
CPU type.  "ARM64" here is not a name of the architecture, but simply
means an ARM CPU that is capable of (and for our case, will only really
be) running in the 64-bit mode (AArch64).

There are no subtypes defined, and none are expected to be defined in
the future.  Support for individual features/extensions should be
discovered by other means, i.e. the aarch64_get_hwcaps() RPC.
---
 include/mach/machine.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/mach/machine.h b/include/mach/machine.h
index 9a176e8c..072bf539 100644
--- a/include/mach/machine.h
+++ b/include/mach/machine.h
@@ -110,6 +110,7 @@ extern struct machine_slot  machine_slot[NCPUS];
 #define CPU_TYPE_PENTIUMPRO((cpu_type_t) 19)
 #define CPU_TYPE_POWERPC   ((cpu_type_t) 20)
 #define CPU_TYPE_X86_64((cpu_type_t) 21)
+#define CPU_TYPE_ARM64 ((cpu_type_t) 22)   /* AArch64-capable ARM 
*/
 
 /*
  * Machine subtypes (these are defined here, instead of in a machine
-- 
2.44.0




Re: [PATCH v2 2/3] aarch64: Add support for aarch64-gnu (GNU/Hurd on AArch64)

2024-04-09 Thread Sergey Bugaev
On Tue, Apr 9, 2024 at 7:24 PM Palmer Dabbelt  wrote:
> > I assume the buildbot failure that I just got an email about is
> > unrelated; it's failing on some RISC-V thing.
>
> Sorry if I missed something here, do you have a pointer?

The buildbot failure emails reference [0] and [1].

[0]: https://builder.sourceware.org/buildbot/#/builders/269/builds/4216
[1]: https://builder.sourceware.org/buildbot/#/builders/269/builds/4218

 Specifically, the "git diff_1" step seems to be failing with

diff --git a/gcc/config/riscv/riscv.opt.urls
b/gcc/config/riscv/riscv.opt.urls
index da31820e234..351f7f0dda2 100644
--- a/gcc/config/riscv/riscv.opt.urls
+++ b/gcc/config/riscv/riscv.opt.urls
@@ -89,3 +89,5 @@ UrlSuffix(gcc/RISC-V-Options.html#index-minline-strncmp)
 minline-strlen
 UrlSuffix(gcc/RISC-V-Options.html#index-minline-strlen)

+; skipping UrlSuffix for 'mtls-dialect=' due to finding no URLs
+

I don't know what to make of that, but it seems unrelated to my
aarch64-gnu changes.

Sergey



Re: [PATCH v2 2/3] aarch64: Add support for aarch64-gnu (GNU/Hurd on AArch64)

2024-04-09 Thread Sergey Bugaev
On Tue, Apr 9, 2024 at 10:27 AM Thomas Schwinge  wrote:
> Thanks, pushed to trunk branch:
>
>   - commit 532c57f8c3a15b109a46d3e2b14d60a5c40979d5 "Move GNU/Hurd startfile 
> spec from config/i386/gnu.h to config/gnu.h"
>   - commit 9670a2326333caa8482377c00beb65723b7b4b26 "aarch64: Add support for 
> aarch64-gnu (GNU/Hurd on AArch64)"
>   - commit 46c91665f4bceba19aed56f5bd6e934c548b84ff "libgcc: Add basic 
> support for aarch64-gnu (GNU/Hurd on AArch64)"

\o/ Thanks a lot!

This will unblock merging the aarch64-gnu glibc port upstream.

I assume the buildbot failure that I just got an email about is
unrelated; it's failing on some RISC-V thing.

Sergey

P.S. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114629



[PATCH 1/3] vm: Fix use-after-free in vm_map_pageable_scan()

2024-04-05 Thread Sergey Bugaev
When operating on the kernel map, vm_map_pageable_scan() does what
the code itself describes as "HACK HACK HACK HACK": it unlocks the map,
and calls vm_fault_wire() with the map unlocked. This hack is required
to avoid a deadlock in case vm_fault or one of its callees (perhaps, a
pager) needs to allocate memory in the kernel map. The hack relies on
other kernel code being "well-behaved", in particular on that nothing
will do any serious changes to this region of memory while the map is
unlocked, since this region of memory is "owned" by the caller.

This reasoning doesn't apply to the validity of the 'end' entry (the
first entry after the region to be wired), since it's not a part of the
region, and is "owned" by someone else. Once the map is unlocked, the
'end' entry could get deallocated. Alternatively, a different entry
could get inserted after the VM region in front of 'end', which would
break the 'for (entry = start; entry != end; entry = entry->vme_next)'
loop condition.

This was not an issue in the original Mach 3 kernel, since it used an
address range check for the loop condition, but got broken in commit
023401c5b97023670a44059a60eb2a3a11c8a929 "VM: rework map entry wiring".
Fix this by switching the iteration back to use an address check.

This partly fixes a deadlock with concurrent mach_port_names() calls on
SMP, which was

Reported-by: Damien Zammit 
---
 vm/vm_map.c | 26 --
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/vm/vm_map.c b/vm/vm_map.c
index 7db76b7b..6c06f064 100644
--- a/vm/vm_map.c
+++ b/vm/vm_map.c
@@ -1419,13 +1419,13 @@ vm_map_entry_reset_wired(vm_map_t map, vm_map_entry_t 
entry)
  * is downgraded to a read lock. The caller should always consider
  * the map read locked on return.
  */
-static void
-vm_map_pageable_scan(struct vm_map *map,
-struct vm_map_entry *start,
-struct vm_map_entry *end)
+static void vm_map_pageable_scan(
+   vm_map_tmap,
+   vm_map_entry_t  start_entry,
+   vm_offset_t end)
 {
-   struct vm_map_entry *entry;
-   boolean_t do_wire_faults;
+   vm_map_entry_t  entry;
+   boolean_t   do_wire_faults;
 
/*
 * Pass 1. Update counters and prepare wiring faults.
@@ -1433,7 +1433,10 @@ vm_map_pageable_scan(struct vm_map *map,
 
do_wire_faults = FALSE;
 
-   for (entry = start; entry != end; entry = entry->vme_next) {
+   for (entry = start_entry;
+(entry != vm_map_to_entry(map)) &&
+(entry->vme_start < end);
+entry = entry->vme_next) {
 
/*
 * Unwiring.
@@ -1558,7 +1561,10 @@ vm_map_pageable_scan(struct vm_map *map,
vm_map_lock_write_to_read(map);
}
 
-   for (entry = start; entry != end; entry = entry->vme_next) {
+   for (entry = start_entry;
+(entry != vm_map_to_entry(map)) &&
+(entry->vme_end <= end);
+entry = entry->vme_next) {
/*
 * The wiring count can only be 1 if it was
 * incremented by this function right before
@@ -1683,7 +1689,7 @@ kern_return_t vm_map_protect(
current = next;
 
/* Returns with the map read-locked if successful */
-   vm_map_pageable_scan(map, entry, current);
+   vm_map_pageable_scan(map, entry, end);
 
vm_map_unlock(map);
return(KERN_SUCCESS);
@@ -1822,7 +1828,7 @@ kern_return_t vm_map_pageable(
}
 
/* Returns with the map read-locked */
-   vm_map_pageable_scan(map, start_entry, end_entry);
+   vm_map_pageable_scan(map, start_entry, end);
 
if (lock_map) {
vm_map_unlock(map);
-- 
2.44.0




[PATCH 2/3] vm: Don't attempt to extend in-transition entries

2024-04-05 Thread Sergey Bugaev
The in-transition mechanism exists to make it possible to unlock a map
while still making sure some VM entries won't disappear from under you.
This is currently used by the VM copyin mechanics.

Entries in this state are better left alone, and extending/coalescing is
only an optimization, so it makes sense to skip it if the entry to be
extended is in transition. vm_map_coalesce_entry() already checks for
this; check for it in other similar places too.

This is in preparation for using the in-transition mechanism for wiring,
where it's much more important that the entries are not extended while
in transition.
---
 vm/vm_map.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/vm/vm_map.c b/vm/vm_map.c
index 6c06f064..6bfc527f 100644
--- a/vm/vm_map.c
+++ b/vm/vm_map.c
@@ -821,6 +821,7 @@ kern_return_t vm_map_find_entry(
(entry->vme_end == start) &&
(!entry->is_shared) &&
(!entry->is_sub_map) &&
+   (!entry->in_transition) &&
(entry->object.vm_object == object) &&
(entry->needs_copy == FALSE) &&
(entry->inheritance == VM_INHERIT_DEFAULT) &&
@@ -1055,6 +1056,7 @@ kern_return_t vm_map_enter(
(entry->vme_end == start) &&
(!entry->is_shared) &&
(!entry->is_sub_map) &&
+   (!entry->in_transition) &&
(entry->inheritance == inheritance) &&
(entry->protection == cur_protection) &&
(entry->max_protection == max_protection) &&
@@ -1090,6 +1092,7 @@ kern_return_t vm_map_enter(
(next_entry->vme_start == end) &&
(!next_entry->is_shared) &&
(!next_entry->is_sub_map) &&
+   (!next_entry->in_transition) &&
(next_entry->inheritance == inheritance) &&
(next_entry->protection == cur_protection) &&
(next_entry->max_protection == max_protection) &&
@@ -3054,6 +3057,7 @@ kern_return_t vm_map_copyout_page_list(
last->inheritance != VM_INHERIT_DEFAULT ||
last->protection != VM_PROT_DEFAULT ||
last->max_protection != VM_PROT_ALL ||
+   last->in_transition ||
(must_wire ? (last->wired_count == 0)
   : (last->wired_count != 0))) {
goto create_object;
-- 
2.44.0




[PATCH 3/3] vm: Mark entries as in-transition while wiring down

2024-04-05 Thread Sergey Bugaev
When operating on the kernel map, vm_map_pageable_scan() does what
the code itself describes as "HACK HACK HACK HACK": it unlocks the map,
and calls vm_fault_wire() with the map unlocked. This hack is required
to avoid a deadlock in case vm_fault or one of its callees (perhaps, a
pager) needs to allocate memory in the kernel map. The hack relies on
other kernel code being "well-behaved", in particular on that nothing
will do any serious changes to this region of memory while the map is
unlocked, since this region of memory is "owned" by the caller.

Even if the kernel code is "well-behaved" and doesn't alter VM regions
that it doesn't "own", it can still access adjacent regions. While this
doesn't affect the region being wired down as such, it can still end up
causing trouble due to extension & coalescence (merging) of VM entries.

VM entry coalescence is an optimization where two adjacent VM entries
with identical properties are merged into a single one that spans the
combined region of the two original entries. VM entry extension is a
similar an optimization where an existing VM entry is extended to cover
an adjacent region, instead of a new VM entry being created to describe
the region.

These optimizations are a private implementation detail of vm_map, and
(while they can be observed through e.g. vm_region) they are not
supposed to cause any visible effects to how the described regions of
memory behave; coalescence/extension and clipping happen automatically
as needed when adding or removing mappings, or changing their
properties. This is why it's fine for "well-behaved" kernel code to
unknowingly cause extension or coalescence of VM entries describing a
region by operating on adjacent VM regions.

The "HACK HACK HACK HACK" code path relies on the VM entries in the
region staying intact while it keeps the map unlocked, as it passes
direct pointers to the entries into vm_fault_wire(), and also walks the
list of entries in the region by following the vme_next pointers in the
entries. Yet, this assumption is violated by the entries getting
concurrently modified by other kernel code operating on adjacent VM
regions, as described above. This is not only undefined behavior in the
sense of the C language standard, but can also cause very real issues.

Specifically, we've been seeing the VM subsystem deadlock when building
Mach with SMP support and running a test program that calls
mach_port_names() concurrently and repearedly. mach_port_names()
implementation allocates and wires down memory, and when called from
multiple threads, it was likely to allocate, and wire, several adjacent
regions of memory, which would then cause entry coalescence/extension
and clipping to kick in. The specific sequence of events that led to a
deadlock appear to have been:

1. Multiple threads execute mach_port_names() concurrently.
2. One of the threads is wiring down a memory region, another is
   unwiring an adjacent memory region.
3. The wiring thread has unlocked the ipc_kernel_map, and called into
   vm_fault_wire().
4. Due to entry coalescence/extension, the entry the wiring thread was
   going to wire down now describes a broader region of memory, namely
   it includes an adjustent region of memory that has previously been
   wired down by the other thread that is about to unwire it.
5. The wiring thread sets the busy bit on a wired-down page that the
   unwiring thread is about to unwire, and is waiting to take the map
   lock for reading in vm_map_verify().
6. The unwiring thread holds the map lock for writing, and is waiting
   for the page to lose its busy bit.
7. Deadlock!

To prevent this from happening, we have to ensure that the VM entries,
at least as passed into vm_fault_wire() and as used for walking the list
of such entries, stay intact while we have the map unlocked. One simple
way to achieve that that I have proposed previously is to make a
temporary copy of the VM entries in the region, and pass the copies into
vm_fault_wire(). The entry copies would not be affected by coalescence/
extension, even if the original entries in the map are. This is however
only straigtforward to do when there's just a single entry describing
the while region, and there are further concerns with e.g. whether the
underlying memory objects could, too, get coalesced.

Arguably, making copies of the memory entries is making the hack even
bigger. This patch instead implements a relatively clean solution that,
arguably, makes the whole thing less of a hack: namely, making use of
the in-transition bit on VM entries to prevent coalescence and any other
unwanted effects. The entry in-transition bit was introduced for a very
similar use case: the VM map copyout logic has to temporarily unlock the
map to run its continuation, so it marks the VM entries it copied out
into the map up to that point as being "in transition", asking other
code to hold off making any serious changes to those entries. There's a
companion "needs wakeup" bit that 

Re: [PATCH v2 2/3] aarch64: Add support for aarch64-gnu (GNU/Hurd on AArch64)

2024-04-05 Thread Sergey Bugaev
Hello,

On Tue, Apr 2, 2024 at 8:26 PM Richard Sandiford
 wrote:
> I don't know if you're waiting on me, but just in case: this and patch 3
> still LGTM if Thomas is OK with them.

Thanks. Thomas asked me to resubmit with Changelog entries added (but
hasn't pointed out anything else), so this is waiting for him to
confirm that this looks OK now.

Sergey



[PATCH mig 2/2] Add support for MACH_MSG_TYPE_COPY_SEND_ONCE

2024-04-01 Thread Sergey Bugaev
---
 cpu.sym  | 2 ++
 lexxer.l | 1 +
 2 files changed, 3 insertions(+)

diff --git a/cpu.sym b/cpu.sym
index 1ac2fae..fe208c9 100644
--- a/cpu.sym
+++ b/cpu.sym
@@ -69,6 +69,8 @@ expr MACH_MSG_TYPE_COPY_SEND
 expr MACH_MSG_TYPE_MAKE_SEND
 /* Must hold receive rights */
 expr MACH_MSG_TYPE_MAKE_SEND_ONCE
+/* Must hold sendonce rights */
+expr MACH_MSG_TYPE_COPY_SEND_ONCE
 
 /*
  *  Values received/carried in messages.  Tells the receiver what
diff --git a/lexxer.l b/lexxer.l
index 6e2234e..cd4ef3d 100644
--- a/lexxer.l
+++ b/lexxer.l
@@ -180,6 +180,7 @@ static void doSharp(const char *body); /* process body of # 
directives */
 "MACH_MSG_TYPE_MOVE_SEND"  
TPRETURN(MACH_MSG_TYPE_MOVE_SEND,MACH_MSG_TYPE_PORT_SEND,port_size_in_bits);
 "MACH_MSG_TYPE_MAKE_SEND_ONCE" 
TPRETURN(MACH_MSG_TYPE_MAKE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,port_size_in_bits);
 "MACH_MSG_TYPE_MOVE_SEND_ONCE" 
TPRETURN(MACH_MSG_TYPE_MOVE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,port_size_in_bits);
+"MACH_MSG_TYPE_COPY_SEND_ONCE" 
TPRETURN(MACH_MSG_TYPE_COPY_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,port_size_in_bits);
 
 "MACH_MSG_TYPE_PORT_NAME"  
TRETURN(MACH_MSG_TYPE_PORT_NAME,port_name_size_in_bits);
 "MACH_MSG_TYPE_PORT_RECEIVE"   
TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_RECEIVE,port_size_in_bits);
-- 
2.44.0




[PATCH gnumach 1/2] Add MACH_MSG_TYPE_COPY_SEND_ONCE

2024-04-01 Thread Sergey Bugaev
Mach allows messages to carry port rights along with data; the rights
contained in a message are transferred from the sender's IPC space to
the receiver.  The sender has to specify exactly how a right that the
message will carry is to be created from the right(s) that the sender
holds: in particular, a send right can be made (created) from a receive
right, copied from another send right, or a send right can be *moved*,
in which case the sender loses its right.

Send-once rights, new in Mach 3, similarly can be made from a receive
right, or moved.  However, it would appear that the original Mach
designers forgot to implement the functionality of *copying* a send-once
right when sending it in a message.

This patch fixes the oversight by adding the missing
MACH_MSG_TYPE_COPY_SEND_ONCE (aka copy-sonce) message type.  It behaves
very similar to MACH_MSG_TYPE_COPY_SEND: the sender must supply an
existing send-once right, so count of send-once references to the port
(ip_sorights) is incremented, and the new send-once right gets carried
in the message.  The receiver sees it as MACH_MSG_TYPE_PORT_SEND_ONCE
(equal to MACH_MSG_TYPE_MOVE_SEND_ONCE), it cannot tell (and should not
care) whether the sender has used make-sonce, move-sonce, or copy-sonce.
It is also possible to supply a dead name when using copy-sonce (no
matter whether the name originally denoted a send or send-once right);
in this case the receiver will get MACH_PORT_DEAD instead of any right,
and the sender keeps its dead name reference.

This patch also adds the mach_port_copy_send_once_t MIG type, which can
be used in routine definitions.  A corresponding MIG patch is required
to make MIG recognise MACH_MSG_TYPE_COPY_SEND_ONCE as a valid type.  To
bootstrap support for MACH_MSG_TYPE_COPY_SEND_ONCE in Mach and MIG, you
should run 'make install-data' in Mach first, then build and install MIG
with make-sonce support, the build Mach.

Note that the other potential COPY type, MACH_MSG_TYPE_COPY_RECEIVE,
makes no sense for obvious reasons: there can only ever be one receive
right for a port, and Mach relies on this being true in a number of
places (e.g. ip_receiver/ip_receiver_name).

Note also that fully supporting MACH_MSG_TYPE_COPY_SEND_ONCE in Mach is
required to take advantage of hardware port translation acceleration on
AArch64 CPUs that implement the FEAT_AFD extension: the MPTTR_EL1 (Mach
Port Translation Type Register) system register must hold a value of
port translation type, which can include MACH_MSG_TYPE_COPY_SEND_ONCE.
---
 doc/mach.texi   |  1 +
 include/mach/mach_port.defs |  1 +
 include/mach/message.h  | 18 +++
 include/mach/std_types.defs |  2 ++
 ipc/ipc_kmsg.c  |  3 ++
 ipc/ipc_object.c| 21 +++-
 ipc/ipc_right.c | 64 +
 7 files changed, 95 insertions(+), 15 deletions(-)

diff --git a/doc/mach.texi b/doc/mach.texi
index f85288e0..317a5930 100644
--- a/doc/mach.texi
+++ b/doc/mach.texi
@@ -1445,6 +1445,7 @@ should be used in preference to 
@code{MACH_MSG_TYPE_INTEGER_32}.
 @item MACH_MSG_TYPE_COPY_SEND
 @item MACH_MSG_TYPE_MAKE_SEND
 @item MACH_MSG_TYPE_MAKE_SEND_ONCE
+@item MACH_MSG_TYPE_COPY_SEND_ONCE
 @end table
 
 The type @code{MACH_MSG_TYPE_PROTECTED_PAYLOAD} is used by the kernel
diff --git a/include/mach/mach_port.defs b/include/mach/mach_port.defs
index 3823bb14..c291a268 100644
--- a/include/mach/mach_port.defs
+++ b/include/mach/mach_port.defs
@@ -277,6 +277,7 @@ routine mach_port_insert_right(
  * MACH_MSG_TYPE_MOVE_SEND
  * MACH_MSG_TYPE_MAKE_SEND_ONCE
  * MACH_MSG_TYPE_MOVE_SEND_ONCE
+ * MACH_MSG_TYPE_COPY_SEND_ONCE
  */
 
 routine mach_port_extract_right(
diff --git a/include/mach/message.h b/include/mach/message.h
index 9790ef98..aa068cab 100644
--- a/include/mach/message.h
+++ b/include/mach/message.h
@@ -357,8 +357,9 @@ _Static_assert (sizeof (mach_msg_type_t) == sizeof 
(mach_msg_type_long_t),
 #define MACH_MSG_TYPE_PORT_SEND_ONCE   MACH_MSG_TYPE_MOVE_SEND_ONCE
 
 #define MACH_MSG_TYPE_PROTECTED_PAYLOAD23
+#define MACH_MSG_TYPE_COPY_SEND_ONCE   24  /* Must hold send-once rights */
 
-#define MACH_MSG_TYPE_LAST 23  /* Last assigned */
+#define MACH_MSG_TYPE_LAST 24  /* Last assigned */
 
 /*
  *  A dummy value.  Mostly used to indicate that the actual value
@@ -372,16 +373,19 @@ _Static_assert (sizeof (mach_msg_type_t) == sizeof 
(mach_msg_type_long_t),
  */
 
 #define MACH_MSG_TYPE_PORT_ANY(x)  \
-   (((x) >= MACH_MSG_TYPE_MOVE_RECEIVE) && \
-((x) <= MACH_MSG_TYPE_MAKE_SEND_ONCE))
+   x) >= MACH_MSG_TYPE_MOVE_RECEIVE) &&\
+((x) <= MACH_MSG_TYPE_MAKE_SEND_ONCE)) ||  \
+((x) == MACH_MSG_TYPE_COPY_SEND_ONCE))
 
 #defineMACH_MSG_TYPE_PORT_ANY_SEND(x)  \
-   (((x) >= MACH_MSG_TYPE_MOVE_SEND) &&\
-

Re: [PATCH] elf-load: Respect PT_GNU_STACK

2024-03-28 Thread Sergey Bugaev
On Wed, Mar 27, 2024 at 9:37 PM Samuel Thibault  wrote:
> But it's not getting used anywhere?

Indeed, I forgot to extract the kern/bootstrap.c part of the change.
Ooops :) Thanks for pointing it out.

Sergey

-- >8 --

If a bootstrap ELF contains a PT_GNU_STACK phdr, take stack protection
from there.  Otherwise, default to VM_PROT_ALL.
---
 include/mach/exec/elf.h  | 1 +
 include/mach/exec/exec.h | 2 ++
 kern/bootstrap.c | 8 
 kern/elf-load.c  | 7 +++
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/include/mach/exec/elf.h b/include/mach/exec/elf.h
index 9e4f8f7e..55304496 100644
--- a/include/mach/exec/elf.h
+++ b/include/mach/exec/elf.h
@@ -300,6 +300,7 @@ typedef struct {
 #define PT_NOTE4
 #define PT_SHLIB   5
 #define PT_PHDR6
+#define PT_GNU_STACK   0x6474e551
 
 #define PT_LOPROC  0x7000
 #define PT_HIPROC  0x7fff
diff --git a/include/mach/exec/exec.h b/include/mach/exec/exec.h
index 94b234b0..29fa897d 100644
--- a/include/mach/exec/exec.h
+++ b/include/mach/exec/exec.h
@@ -51,6 +51,8 @@ typedef struct exec_info
/* (ELF) Address of interpreter string for loading shared libraries, 
null if none.  */
vm_offset_t interp;
 
+   /* Required stack protection.  */
+   vm_prot_t stack_prot;
 } exec_info_t;
 
 typedef int exec_sectype_t;
diff --git a/kern/bootstrap.c b/kern/bootstrap.c
index 49358ac6..0470e1b6 100644
--- a/kern/bootstrap.c
+++ b/kern/bootstrap.c
@@ -620,10 +620,10 @@ build_args_and_stack(struct exec_info *boot_exec_info,
stack_size = round_page(STACK_SIZE);
stack_base = user_stack_low(stack_size);
 
-   (void) vm_allocate(current_task()->map,
-   _base,
-   stack_size,
-   FALSE);
+   (void) vm_map(current_map(), _base, stack_size,
+ 0, FALSE, IP_NULL, 0, FALSE,
+ boot_exec_info->stack_prot, VM_PROT_ALL,
+ VM_INHERIT_DEFAULT);
 
arg_pos = (char *)
set_user_regs(stack_base, stack_size, boot_exec_info, arg_len);
diff --git a/kern/elf-load.c b/kern/elf-load.c
index ce86327c..596233a8 100644
--- a/kern/elf-load.c
+++ b/kern/elf-load.c
@@ -73,6 +73,8 @@ int exec_load(exec_read_func_t *read, exec_read_exec_func_t 
*read_exec,
if (actual < phsize)
return EX_CORRUPT;
 
+   out_info->stack_prot = VM_PROT_ALL;
+
for (i = 0; i < x.e_phnum; i++)
{
ph = (Elf_Phdr *)((vm_offset_t)phdr + i * x.e_phentsize);
@@ -89,6 +91,11 @@ int exec_load(exec_read_func_t *read, exec_read_exec_func_t 
*read_exec,
  ph->p_vaddr + loadbase, 
ph->p_memsz, type);
if (result)
return result;
+   } else if (ph->p_type == PT_GNU_STACK) {
+   out_info->stack_prot = 0;
+   if (ph->p_flags & PF_R) out_info->stack_prot |= 
VM_PROT_READ;
+   if (ph->p_flags & PF_W) out_info->stack_prot |= 
VM_PROT_WRITE;
+   if (ph->p_flags & PF_X) out_info->stack_prot |= 
VM_PROT_EXECUTE;
}
}
 
-- 
2.44.0




[PATCH 16/17] tests: Don't ask for executable stack

2024-03-27 Thread Sergey Bugaev
---
 tests/start.S| 2 ++
 tests/syscalls.S | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/tests/start.S b/tests/start.S
index b795bfbd..15970fb9 100644
--- a/tests/start.S
+++ b/tests/start.S
@@ -26,3 +26,5 @@ _start:
 movq%rsp,%rdi
 callq   c_start
 #endif /* __x86_64__ */
+
+   .section .note.GNU-stack,"",%progbits
diff --git a/tests/syscalls.S b/tests/syscalls.S
index df9c9bc0..b1e18aa8 100644
--- a/tests/syscalls.S
+++ b/tests/syscalls.S
@@ -2,3 +2,5 @@
 #include 
 
 kernel_trap(invalid_syscall,-31,0)
+
+   .section .note.GNU-stack,"",%progbits
-- 
2.44.0




[PATCH 00/17] Preparatory patches

2024-03-27 Thread Sergey Bugaev
These are generic, relatively independent patches from the AArch64
branch. I've done a quick build for i386-gnu and things still seem to
build, but please test!

Sergey



[PATCH 04/17] Load 64-bit ELFs on all 64-bit ports

2024-03-27 Thread Sergey Bugaev
Not only on x86_64.
---
 include/mach/exec/elf.h | 4 ++--
 kern/exception.c| 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/mach/exec/elf.h b/include/mach/exec/elf.h
index 42920e25..55304496 100644
--- a/include/mach/exec/elf.h
+++ b/include/mach/exec/elf.h
@@ -212,7 +212,7 @@ typedef struct elf64_sym {
 Elf64_Xwordst_size;
 } Elf64_Sym;
 
-#ifdef __x86_64__
+#ifdef __LP64__
 #define Elf_Sym Elf64_Sym
 #define Elf_Shdr Elf64_Shdr
 #else
@@ -350,7 +350,7 @@ typedef struct {
 #define DT_TEXTREL 22
 #define DT_JMPREL  23
 
-#if defined(__x86_64__) && ! defined(USER32)
+#if defined(__LP64__) && ! defined(USER32)
 typedef Elf64_Ehdr Elf_Ehdr;
 typedef Elf64_Phdr Elf_Phdr;
 #else
diff --git a/kern/exception.c b/kern/exception.c
index 15f29705..7139b466 100644
--- a/kern/exception.c
+++ b/kern/exception.c
@@ -283,7 +283,7 @@ struct mach_exception {
 #defineINTEGER_T_SIZE_IN_BITS  (8 * sizeof(integer_t))
 #defineINTEGER_T_TYPE  MACH_MSG_TYPE_INTEGER_T
 #define RPC_LONG_INTEGER_T_SIZE_IN_BITS(8 * sizeof(rpc_long_integer_t))
-#if defined(__x86_64__) && !defined(USER32)
+#if defined(__LP64__) && !defined(USER32)
 #define RPC_LONG_INTEGER_T_TYPEMACH_MSG_TYPE_INTEGER_64
 #else
 #define RPC_LONG_INTEGER_T_TYPEMACH_MSG_TYPE_INTEGER_32
-- 
2.44.0




[PATCH 02/17] Disable host_kernel_version() everywhere but on i386

2024-03-27 Thread Sergey Bugaev
It's not only x86_64, none of new architectures are going to have it.
---
 include/mach/mach_host.defs | 6 +++---
 kern/host.c | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/mach/mach_host.defs b/include/mach/mach_host.defs
index a8c40af6..8fd9d6b3 100644
--- a/include/mach/mach_host.defs
+++ b/include/mach/mach_host.defs
@@ -161,9 +161,7 @@ routine task_get_assignment(
task: task_t;
out assigned_set: processor_set_name_t);
 
-#if defined(__x86_64__) && !defined(USER32)
-skip;
-#else
+#if defined(__i386__) || (defined(__x86_64__) && defined(USER32))
 /*
  * Get string describing current kernel version.
  * Deprecated, use host_get_kernel_version.
@@ -171,6 +169,8 @@ skip;
 routinehost_kernel_version(
host: host_t;
out kernel_version  : kernel_version_t);
+#else
+skip;
 #endif
 
 /*
diff --git a/kern/host.c b/kern/host.c
index 69394374..53f8bdbd 100644
--- a/kern/host.c
+++ b/kern/host.c
@@ -219,8 +219,8 @@ kern_return_t host_get_kernel_version(
return KERN_SUCCESS;
 }
 
-#if !defined(__x86_64__) || defined(USER32)
-/* Same as above, but does not exist for x86_64.  */
+#if defined(__i386__) || (defined(__x86_64__) && defined(USER32))
+/* Same as above, but only exists on i386.  */
 kern_return_t host_kernel_version(
const host_thost,
kernel_version_tout_version)
-- 
2.44.0




[PATCH 01/17] elf-load: Respect PT_GNU_STACK

2024-03-27 Thread Sergey Bugaev
If a bootstrap ELF contains a PT_GNU_STACK phdr, take stack protection
from there.  Otherwise, default to VM_PROT_ALL.
---
 include/mach/exec/elf.h  | 1 +
 include/mach/exec/exec.h | 2 ++
 kern/elf-load.c  | 7 +++
 3 files changed, 10 insertions(+)

diff --git a/include/mach/exec/elf.h b/include/mach/exec/elf.h
index 409947c4..42920e25 100644
--- a/include/mach/exec/elf.h
+++ b/include/mach/exec/elf.h
@@ -300,6 +300,7 @@ typedef struct {
 #define PT_NOTE4
 #define PT_SHLIB   5
 #define PT_PHDR6
+#define PT_GNU_STACK   0x6474e551
 
 #define PT_LOPROC  0x7000
 #define PT_HIPROC  0x7fff
diff --git a/include/mach/exec/exec.h b/include/mach/exec/exec.h
index 94b234b0..29fa897d 100644
--- a/include/mach/exec/exec.h
+++ b/include/mach/exec/exec.h
@@ -51,6 +51,8 @@ typedef struct exec_info
/* (ELF) Address of interpreter string for loading shared libraries, 
null if none.  */
vm_offset_t interp;
 
+   /* Required stack protection.  */
+   vm_prot_t stack_prot;
 } exec_info_t;
 
 typedef int exec_sectype_t;
diff --git a/kern/elf-load.c b/kern/elf-load.c
index ce86327c..596233a8 100644
--- a/kern/elf-load.c
+++ b/kern/elf-load.c
@@ -73,6 +73,8 @@ int exec_load(exec_read_func_t *read, exec_read_exec_func_t 
*read_exec,
if (actual < phsize)
return EX_CORRUPT;
 
+   out_info->stack_prot = VM_PROT_ALL;
+
for (i = 0; i < x.e_phnum; i++)
{
ph = (Elf_Phdr *)((vm_offset_t)phdr + i * x.e_phentsize);
@@ -89,6 +91,11 @@ int exec_load(exec_read_func_t *read, exec_read_exec_func_t 
*read_exec,
  ph->p_vaddr + loadbase, 
ph->p_memsz, type);
if (result)
return result;
+   } else if (ph->p_type == PT_GNU_STACK) {
+   out_info->stack_prot = 0;
+   if (ph->p_flags & PF_R) out_info->stack_prot |= 
VM_PROT_READ;
+   if (ph->p_flags & PF_W) out_info->stack_prot |= 
VM_PROT_WRITE;
+   if (ph->p_flags & PF_X) out_info->stack_prot |= 
VM_PROT_EXECUTE;
}
}
 
-- 
2.44.0




[PATCH 17/17] tests: Create tests/ in the build tree before trying to use it

2024-03-27 Thread Sergey Bugaev
---
 tests/user-qemu.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/user-qemu.mk b/tests/user-qemu.mk
index fd5ae1ab..4f8390b6 100644
--- a/tests/user-qemu.mk
+++ b/tests/user-qemu.mk
@@ -130,6 +130,7 @@ SRC_TESTLIB= \
$(MIG_GEN_CC)
 
 tests/errlist.c: $(addprefix $(srcdir)/include/mach/,message.h kern_return.h 
mig_errors.h)
+   mkdir -p tests
echo "/* autogenerated file */" >$@
echo "#include " >>$@
echo "#include " >>$@
-- 
2.44.0




[PATCH 05/17] gsync: Use copyin()/copyout() to access user memory

2024-03-27 Thread Sergey Bugaev
Depending on the architecture and setup, it may not be possible to
access user memory directly, for example, due to user mode mappings not
being accessible from kernel mode (x86 SMAP, AArch64 PAN). There are
dedicated machine-specific copyin()/copyout() routines that know how to
access user memory from the kernel; use them.
---
 kern/gsync.c | 38 +++---
 1 file changed, 31 insertions(+), 7 deletions(-)

diff --git a/kern/gsync.c b/kern/gsync.c
index 31b564ca..656e47dd 100644
--- a/kern/gsync.c
+++ b/kern/gsync.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* An entry in the global hash table. */
 struct gsync_hbucket
@@ -254,9 +255,28 @@ kern_return_t gsync_wait (task_t task, vm_offset_t addr,
 
   boolean_t equal;
   if (! remote)
-equal = ((unsigned int *)addr)[0] == lo &&
-  ((flags & GSYNC_QUAD) == 0 ||
-   ((unsigned int *)addr)[1] == hi);
+{
+  unsigned int value;
+
+  if (copyin ((const void *) addr, , 4))
+   {
+ vm_map_unlock_read (task->map);
+ kmutex_unlock (>lock);
+ return KERN_INVALID_ADDRESS;
+   }
+
+  equal = (value == lo);
+  if (flags & GSYNC_QUAD)
+   {
+ if (copyin ((const void *) (addr + 4), , 4))
+   {
+ vm_map_unlock_read (task->map);
+ kmutex_unlock (>lock);
+ return KERN_INVALID_ADDRESS;
+   }
+ equal = equal && (value == hi);
+   }
+}
   else
 {
   vm_offset_t paddr = temp_mapping (, addr, VM_PROT_READ);
@@ -388,11 +408,15 @@ kern_return_t gsync_wake (task_t task,
 }
 
   addr = paddr + (addr & (PAGE_SIZE - 1));
+  *(unsigned int *)addr = val;
+  vm_map_remove (kernel_map, addr, addr + sizeof (int));
+}
+  else if (copyout (, (void *) addr, 4))
+{
+  kmutex_unlock (>lock);
+  vm_map_unlock_read (task->map);
+  return KERN_INVALID_ADDRESS;
 }
-
-  *(unsigned int *)addr = val;
-  if (task != current_task ())
-vm_map_remove (kernel_map, addr, addr + sizeof (int));
 }
 
   vm_map_unlock_read (task->map);
-- 
2.44.0




[PATCH 07/17] kern/rdxtree: Fix undefined behavior

2024-03-27 Thread Sergey Bugaev
Initializing a variable with itself is undefined, and GCC 14 rightfully
produces a warning about the variable being used (to initialize itself)
prior to initialization. X15 sets the variables to 0 instead, so do the
same in Mach.
---
 kern/rdxtree.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kern/rdxtree.c b/kern/rdxtree.c
index a23d6e7e..6d03710c 100644
--- a/kern/rdxtree.c
+++ b/kern/rdxtree.c
@@ -437,7 +437,7 @@ rdxtree_insert_common(struct rdxtree *tree, rdxtree_key_t 
key,
   void *ptr, void ***slotp)
 {
 struct rdxtree_node *node, *prev;
-unsigned int height, shift, index = index;
+unsigned int height, shift, index = 0;
 int error;
 
 assert(ptr != NULL);
@@ -513,7 +513,7 @@ rdxtree_insert_alloc_common(struct rdxtree *tree, void *ptr,
 rdxtree_key_t *keyp, void ***slotp)
 {
 struct rdxtree_node *node, *prev;
-unsigned int height, shift, index = index;
+unsigned int height, shift, index = 0;
 rdxtree_key_t key;
 int error;
 
-- 
2.44.0




[PATCH 12/17] tests: Add a more serious mach_msg_server() routine

2024-03-27 Thread Sergey Bugaev
---
 tests/include/testlib.h |  16 ++
 tests/test-syscalls.c   |  40 +
 tests/testlib.c | 123 
 3 files changed, 142 insertions(+), 37 deletions(-)

diff --git a/tests/include/testlib.h b/tests/include/testlib.h
index cdb2ce13..d2367124 100644
--- a/tests/include/testlib.h
+++ b/tests/include/testlib.h
@@ -70,6 +70,22 @@ thread_t test_thread_start(task_t task, 
void(*routine)(void*), void* arg);
 mach_port_t host_priv(void);
 mach_port_t device_priv(void);
 
+extern void mach_msg_destroy(mach_msg_header_t *msg);
+
+extern mach_msg_return_t mach_msg_server(
+   boolean_t   (*demux) (mach_msg_header_t *request,
+ mach_msg_header_t *reply),
+   mach_msg_size_t max_size,
+   mach_port_t rcv_name,
+   mach_msg_option_t   options);
+
+extern mach_msg_return_t mach_msg_server_once(
+   boolean_t   (*demux) (mach_msg_header_t *request,
+ mach_msg_header_t *reply),
+   mach_msg_size_t max_size,
+   mach_port_t rcv_name,
+   mach_msg_option_t   options);
+
 int main(int argc, char *argv[], int envc, char *envp[]);
 
 #endif /* TESTLIB_H */
diff --git a/tests/test-syscalls.c b/tests/test-syscalls.c
index be4df8c3..63c2690a 100644
--- a/tests/test-syscalls.c
+++ b/tests/test-syscalls.c
@@ -49,44 +49,10 @@ kern_return_t catch_exception_raise(mach_port_t 
exception_port,
   last_exc.exception = exception;
   last_exc.code = code;
   last_exc.subcode = subcode;
+  thread_terminate(thread);
   return KERN_SUCCESS;
 }
 
-static char simple_request_data[PAGE_SIZE];
-static char simple_reply_data[PAGE_SIZE];
-int simple_msg_server(boolean_t (*demuxer) (mach_msg_header_t *request,
- mach_msg_header_t *reply),
-  mach_port_t rcv_port_name,
-  int num_msgs)
-{
-  int midx = 0, mok = 0;
-  int ret;
-  mig_reply_header_t *request = (mig_reply_header_t*)simple_request_data;
-  mig_reply_header_t *reply = (mig_reply_header_t*)simple_reply_data;
-  while ((midx - num_msgs) < 0)
-{
-  ret = mach_msg(>Head, MACH_RCV_MSG, 0, PAGE_SIZE,
- rcv_port_name, 0, MACH_PORT_NULL);
-  switch (ret)
-{
-case MACH_MSG_SUCCESS:
-  if ((*demuxer)(>Head, >Head))
-mok++;  // TODO send reply
-  else
-FAILURE("demuxer didn't handle the message");
-  break;
-default:
-  ASSERT_RET(ret, "receiving in msg_server");
-  break;
-}
-  midx++;
-}
-  if (mok != midx)
-FAILURE("wrong number of message received");
-  return mok != midx;
-}
-
-
 void test_syscall_bad_arg_on_stack(void *arg)
 {
   /* mach_msg() has 7 arguments, so the last one should be always
@@ -152,13 +118,13 @@ int main(int argc, char *argv[], int envc, char *envp[])
 
   memset(_exc, 0, sizeof(last_exc));
   test_thread_start(mach_task_self(), test_bad_syscall_num, NULL);
-  ASSERT_RET(simple_msg_server(exc_server, excp, 1), "error in exc server");
+  ASSERT_RET(mach_msg_server_once(exc_server, 4096, excp, 
MACH_MSG_OPTION_NONE), "error in exc server");
   ASSERT((last_exc.exception == EXC_BAD_INSTRUCTION) && (last_exc.code == 
EXC_I386_INVOP),
  "bad exception for test_bad_syscall_num()");
 
   memset(_exc, 0, sizeof(last_exc));
   test_thread_start(mach_task_self(), test_syscall_bad_arg_on_stack, NULL);
-  ASSERT_RET(simple_msg_server(exc_server, excp, 1), "error in exc server");
+  ASSERT_RET(mach_msg_server_once(exc_server, 4096, excp, 
MACH_MSG_OPTION_NONE), "error in exc server");
   ASSERT((last_exc.exception == EXC_BAD_ACCESS) && (last_exc.code == 
KERN_INVALID_ADDRESS),
  "bad exception for test_syscall_bad_arg_on_stack()");
 
diff --git a/tests/testlib.c b/tests/testlib.c
index d2198830..baf1ce5c 100644
--- a/tests/testlib.c
+++ b/tests/testlib.c
@@ -26,6 +26,7 @@
 #include 
 
 #include 
+#include 
 #include 
 
 
@@ -81,6 +82,128 @@ const char* e2s(int err)
   }
 }
 
+void mach_msg_destroy(mach_msg_header_t *msg)
+{
+   mach_port_t tmp;
+
+   tmp = mach_reply_port();
+
+   msg->msgh_local_port = msg->msgh_remote_port;
+   msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,
+   MACH_MSGH_BITS_REMOTE(msg->msgh_bits))
+| MACH_MSGH_BITS_OTHER(msg->msgh_bits);
+
+   mach_msg(msg, MACH_SEND_MSG, msg->msgh_size, 0, MACH_PORT_NULL,
+MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+   mach_port_mod_refs(mach_task_self(), tmp, MACH_PORT_RIGHT_RECEIVE, -1);
+}
+
+mach_msg_return_t mach_msg_server(
+   boolean_t   (*demux) (mach_msg_header_t *request,
+ mach_msg_header_t *reply),
+   mach_msg_size_t max_size,
+   mach_port_t 

[PATCH 11/17] tests: Fix halt()

2024-03-27 Thread Sergey Bugaev
Mark it as noreturn, and make sure to halt, not reboot.
---
 tests/include/testlib.h | 2 +-
 tests/testlib.c | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/tests/include/testlib.h b/tests/include/testlib.h
index a3f3a6a8..cdb2ce13 100644
--- a/tests/include/testlib.h
+++ b/tests/include/testlib.h
@@ -63,7 +63,7 @@ extern const char* TEST_FAILURE_MARKER;
 
 const char* e2s(int err);
 const char* e2s_gnumach(int err);
-void halt();
+extern void __attribute__((noreturn)) halt();
 int msleep(uint32_t timeout);
 thread_t test_thread_start(task_t task, void(*routine)(void*), void* arg);
 
diff --git a/tests/testlib.c b/tests/testlib.c
index 2eaeb591..d2198830 100644
--- a/tests/testlib.c
+++ b/tests/testlib.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -55,7 +56,7 @@ mach_port_t device_priv(void)
 
 void halt()
 {
-  int ret = host_reboot(host_priv_port, 0);
+  int ret = host_reboot(host_priv_port, RB_HALT);
   ASSERT_RET(ret, "host_reboot() failed!");
   while (1)
 ;
-- 
2.44.0




[PATCH 15/17] tests: Make exception subcode a long

2024-03-27 Thread Sergey Bugaev
---
 tests/test-syscalls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/test-syscalls.c b/tests/test-syscalls.c
index 63c2690a..fbfecd9c 100644
--- a/tests/test-syscalls.c
+++ b/tests/test-syscalls.c
@@ -34,7 +34,7 @@ static struct {
   mach_port_t task;
   integer_t exception;
   integer_t code;
-  integer_t subcode;
+  long_integer_t subcode;
 } last_exc;
 kern_return_t catch_exception_raise(mach_port_t exception_port,
 mach_port_t thread, mach_port_t task,
-- 
2.44.0




[PATCH 06/17] kern/syscall_subr.c: Use copyin()/copyout() to access user memory

2024-03-27 Thread Sergey Bugaev
It's not always possible to directly access user memory from kernel
mode. While it's in theory a lot more expensive to fetch each character
to be printed separately, mach_print() is only a debugging facility, and
it's not supposed to be used for printing large amounts of data.
---
 kern/syscall_subr.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/kern/syscall_subr.c b/kern/syscall_subr.c
index e0057d94..0027be29 100644
--- a/kern/syscall_subr.c
+++ b/kern/syscall_subr.c
@@ -43,6 +43,7 @@
 #include 
 #include 
 #include/* for splsched */
+#include /* for copyin */
 
 #ifMACH_FIXPRI
 #include 
@@ -381,6 +382,14 @@ thread_depress_abort(thread_t thread)
 void
 mach_print(const char *s)
 {
-   printf("%s", s);
+   charc;
+   while (TRUE) {
+   if (copyin(s, , 1))
+   return;
+   if (c == 0)
+   break;
+   printf("%c", c);
+   s++;
+   }
 }
 #endif /* MACH_KDB */
-- 
2.44.0




[PATCH 09/17] Move copy{in,out}msg declarations to copy_user.h

2024-03-27 Thread Sergey Bugaev
Since they are implemented in copy_user.c
---
 i386/i386/locore.h |  4 
 ipc/copy_user.h| 15 +++
 kern/exception.c   |  1 +
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/i386/i386/locore.h b/i386/i386/locore.h
index 217e6dec..8ff587ed 100644
--- a/i386/i386/locore.h
+++ b/i386/i386/locore.h
@@ -52,10 +52,6 @@ extern int copyinmsg (const void *userbuf, void *kernelbuf, 
size_t cn, size_t kn
 extern int copyout (const void *kernelbuf, void *userbuf, size_t cn);
 #ifdef USER32
 extern int copyoutmsg (const void *kernelbuf, void *userbuf, size_t cn);
-#else
-static inline int copyoutmsg (const void *kernelbuf, void *userbuf, size_t cn) 
{
-   return copyout (kernelbuf, userbuf, cn);
-}
 #endif
 
 extern int inst_fetch (int eip, int cs);
diff --git a/ipc/copy_user.h b/ipc/copy_user.h
index a57b3ee5..33beacd0 100644
--- a/ipc/copy_user.h
+++ b/ipc/copy_user.h
@@ -25,6 +25,21 @@
 #include 
 #include 
 
+int copyinmsg(
+   const void  *userbuf,
+   void*kernelbuf,
+   size_t  usize,
+   size_t  ksize);
+
+#ifdef USER32
+int copyoutmsg(
+   const void  *kernelbuf,
+   void*userbuf,
+   size_t  ksize);
+#else
+#define copyoutmsg copyout
+#endif
+
 /*
  * The copyin_32to64() and copyout_64to32() routines are meant for data types
  * that have different size in kernel and user space. They should be 
independent
diff --git a/kern/exception.c b/kern/exception.c
index 7139b466..cc023d45 100644
--- a/kern/exception.c
+++ b/kern/exception.c
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
-- 
2.44.0




[PATCH 13/17] tests: Add vm_page_size

2024-03-27 Thread Sergey Bugaev
---
 tests/include/testlib.h |  2 ++
 tests/testlib.c | 13 +
 2 files changed, 15 insertions(+)

diff --git a/tests/include/testlib.h b/tests/include/testlib.h
index d2367124..035fdc28 100644
--- a/tests/include/testlib.h
+++ b/tests/include/testlib.h
@@ -70,6 +70,8 @@ thread_t test_thread_start(task_t task, 
void(*routine)(void*), void* arg);
 mach_port_t host_priv(void);
 mach_port_t device_priv(void);
 
+extern vm_size_t vm_page_size;
+
 extern void mach_msg_destroy(mach_msg_header_t *msg);
 
 extern mach_msg_return_t mach_msg_server(
diff --git a/tests/testlib.c b/tests/testlib.c
index baf1ce5c..12c5e771 100644
--- a/tests/testlib.c
+++ b/tests/testlib.c
@@ -29,6 +29,11 @@
 #include 
 #include 
 
+#ifdef PAGE_SIZE
+vm_size_t vm_page_size = PAGE_SIZE;
+#else
+vm_size_t vm_page_size;
+#endif
 
 static int argc = 0;
 static char *argv_unknown[] = {"unknown", "m1", "123", "456"};
@@ -212,6 +217,7 @@ mach_msg_return_t mach_msg_server_once(
 void __attribute__((used, retain))
 c_start(void **argptr)
 {
+  kern_return_t kr;
   intptr_t* argcptr = (intptr_t*)argptr;
   argc = argcptr[0];
   argv = (char **) [1];
@@ -224,6 +230,13 @@ c_start(void **argptr)
   mach_atoi(argv[1], _priv_port);
   mach_atoi(argv[2], _master_port);
 
+#ifndef PAGE_SIZE
+  vm_statistics_data_t stats;
+  kr = vm_statistics (mach_task_self(), );
+  ASSERT_RET(kr, "can't get page size");
+  vm_page_size = stats.pagesize;
+#endif
+
   printf("started %s", argv[0]);
   for (int i=1; i

[PATCH 14/17] tests: Use vm_page_size

2024-03-27 Thread Sergey Bugaev
---
 tests/testlib_thread_start.c | 19 +++
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/tests/testlib_thread_start.c b/tests/testlib_thread_start.c
index fa8af0ea..df4b19ab 100644
--- a/tests/testlib_thread_start.c
+++ b/tests/testlib_thread_start.c
@@ -30,30 +30,33 @@
 #include 
 #include 
 
-/* This is just a temporary mapping to set up the stack */
-static long stack_top[PAGE_SIZE/sizeof(long)] __attribute__ ((aligned 
(PAGE_SIZE)));
-
 thread_t test_thread_start(task_t task, void(*routine)(void*), void* arg) {
-  const vm_size_t stack_size = PAGE_SIZE * 16;
+  const vm_size_t stack_size = vm_page_size * 16;
   kern_return_t ret;
-  vm_address_t stack;
+  vm_address_t stack, local_stack;
+
+  ret = vm_allocate(mach_task_self(), _stack, vm_page_size, TRUE);
+  ASSERT_RET(ret, "can't allocate local stack");
 
   ret = vm_allocate(task, , stack_size, TRUE);
   ASSERT_RET(ret, "can't allocate the stack for a new thread");
 
-  ret = vm_protect(task, stack, PAGE_SIZE, FALSE, VM_PROT_NONE);
+  ret = vm_protect(task, stack, vm_page_size, FALSE, VM_PROT_NONE);
   ASSERT_RET(ret, "can't protect the stack from overflows");
 
-  long *top = (long*)((vm_offset_t)stack_top + PAGE_SIZE) - 1;
+  long *top = (long*)(local_stack + vm_page_size) - 1;
 #ifdef __i386__
   *top = (long)arg; /* The argument is passed on the stack on x86_32 */
   *(top - 1) = 0;   /* The return address */
 #elif defined(__x86_64__)
   *top = 0; /* The return address */
 #endif
-  ret = vm_write(task, stack + stack_size - PAGE_SIZE, (vm_offset_t)stack_top, 
PAGE_SIZE);
+  ret = vm_write(task, stack + stack_size - vm_page_size, local_stack, 
vm_page_size);
   ASSERT_RET(ret, "can't initialize the stack for the new thread");
 
+  ret = vm_deallocate(mach_task_self(), local_stack, vm_page_size);
+  ASSERT_RET(ret, "can't deallocate local stack");
+
   thread_t thread;
   ret = thread_create(task, );
   ASSERT_RET(ret, "thread_create()");
-- 
2.44.0




[PATCH 10/17] Make -fno-PIE etc. architecture-dependent

2024-03-27 Thread Sergey Bugaev
There might be good reasons why Mach on x86 shouldn't be built as PIC/
PIE, but there are also very good reasons to support PIE on other
architectures. Potentially implementing KASLR is one such reason; but
also the Linux AArch64 boot protocol (that the AArch64 port will use for
booting) lets the bootloader load the kernel image at any address,
which makes PIC pretty much required.
---
 Makefile.am  | 4 
 i386/Makefrag.am | 4 
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index ad38249b..357e8470 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -79,10 +79,6 @@ AM_CFLAGS += \
-fno-stack-protector
 endif
 
-# We do not support or need position-independent
-AM_CFLAGS += \
-   -no-pie -fno-PIE -fno-pie -fno-pic
-
 # This must be the same size as port names, see e.g. ipc/ipc_entry.c
 AM_CFLAGS += -DRDXTREE_KEY_32
 
diff --git a/i386/Makefrag.am b/i386/Makefrag.am
index 5e7d4740..7a339417 100644
--- a/i386/Makefrag.am
+++ b/i386/Makefrag.am
@@ -170,6 +170,10 @@ gnumach_LINKFLAGS += \
-T '$(srcdir)'/i386/ldscript
 endif
 
+# We do not support or need position-independent
+AM_CFLAGS += \
+   -no-pie -fno-PIE -fno-pie -fno-pic
+
 AM_CFLAGS += \
-mno-3dnow \
-mno-mmx \
-- 
2.44.0




[PATCH 08/17] ipc: Turn ipc_entry_lookup_failed() into a macro

2024-03-27 Thread Sergey Bugaev
ipc_entry_lookup_failed() is used with both mach_msg_user_header_t and
mach_msg_header_t arguments, which are different types. Make it into a
macro, so it works with both.
---
 ipc/ipc_space.h | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/ipc/ipc_space.h b/ipc/ipc_space.h
index 96d58942..9adbd3f7 100644
--- a/ipc/ipc_space.h
+++ b/ipc/ipc_space.h
@@ -159,15 +159,19 @@ ipc_entry_lookup(
 
 extern volatile boolean_t mach_port_deallocate_debug;
 
-static inline void
-ipc_entry_lookup_failed(mach_msg_header_t *msg, mach_port_name_t name)
-{
-   if (name == MACH_PORT_NAME_NULL || name == MACH_PORT_NAME_DEAD)
-   return;
-   printf("task %.*s looked up a bogus port %lu for %d, most probably a 
bug.\n", (int) sizeof current_task()->name, current_task()->name, (unsigned 
long) name, msg->msgh_id);
-   if (mach_port_deallocate_debug)
-   SoftDebugger("ipc_entry_lookup");
-}
+#define ipc_entry_lookup_failed(msg, port_name)
\
+MACRO_BEGIN\
+   if (MACH_PORT_NAME_VALID(port_name)) {  \
+   printf("task %.*s looked up a bogus port %lu for %d, "  \
+  "most probably a bug.\n",\
+   (int) sizeof current_task()->name,  \
+   current_task()->name,   \
+   (unsigned long) (port_name),\
+   (msg)->msgh_id);\
+   if (mach_port_deallocate_debug) \
+   SoftDebugger("ipc_entry_lookup");   \
+   }   \
+MACRO_END
 
 /*
  * Routine:ipc_entry_get
-- 
2.44.0




[PATCH 03/17] Use the x86_64 message ABI on all 64-bit ports

2024-03-27 Thread Sergey Bugaev
---
 include/mach/message.h | 10 +-
 ipc/ipc_kmsg.c |  4 ++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/mach/message.h b/include/mach/message.h
index 9790ef98..87b83951 100644
--- a/include/mach/message.h
+++ b/include/mach/message.h
@@ -240,7 +240,7 @@ typedef struct {
 } mach_port_name_inlined_t;
 
 typedef struct  {
-#ifdef __x86_64__
+#ifdef __LP64__
 /*
  * For 64 bits, this struct is 8 bytes long so we
  * can pack the same amount of information as mach_msg_type_long_t.
@@ -275,9 +275,9 @@ typedef struct  {
 } __attribute__ ((aligned (__alignof__ (uintptr_t mach_msg_type_t;
 
 typedef struct {
-#ifdef __x86_64__
+#ifdef __LP64__
 union {
-/* On x86_64 this is equivalent to mach_msg_type_t so use
+/* On 64-bit this is equivalent to mach_msg_type_t so use
  * union to overlay with the old field names.  */
 mach_msg_type_tmsgtl_header;
 struct {
@@ -298,7 +298,7 @@ typedef struct {
 #endif
 } __attribute__ ((aligned (__alignof__ (uintptr_t mach_msg_type_long_t;
 
-#ifdef __x86_64__
+#ifdef __LP64__
 #ifdef __cplusplus
 #if __cplusplus >= 201103L
 static_assert (sizeof (mach_msg_type_t) == sizeof (mach_msg_type_long_t),
@@ -401,7 +401,7 @@ typedef integer_t mach_msg_option_t;
 
 #define MACH_SEND_ALWAYS   0x0001  /* internal use only */
 
-#ifdef __x86_64__
+#ifdef __LP64__
 #if defined(KERNEL) && defined(USER32)
 #define MACH_MSG_USER_ALIGNMENT 4
 #else
diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c
index 179c43fa..b23cae7c 100644
--- a/ipc/ipc_kmsg.c
+++ b/ipc/ipc_kmsg.c
@@ -1357,7 +1357,7 @@ ipc_kmsg_copyin_body(
 
if ((is_port && !is_inline && (size != 
PORT_NAME_T_SIZE_IN_BITS)) ||
(is_port && is_inline && (size != PORT_T_SIZE_IN_BITS)) ||
-#ifndef __x86_64__
+#ifndef __LP64__
(longform && ((type->msgtl_header.msgt_name != 0) ||
  (type->msgtl_header.msgt_size != 0) ||
  (type->msgtl_header.msgt_number != 0))) ||
@@ -2876,7 +2876,7 @@ 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__
+#ifndef __LP64__
(longform && ((type->msgtl_header.msgt_name != 0) ||
  (type->msgtl_header.msgt_size != 0) ||
  (type->msgtl_header.msgt_number != 0))) ||
-- 
2.44.0




Re: [RFC PATCH 03/23] Allow glibc to be compiled without EXEC_PAGESIZE

2024-03-25 Thread Sergey Bugaev
Hello,

On Mon, Mar 25, 2024 at 2:58 PM Florian Weimer  wrote:
> > I think the intent here is to initialize _dl_pagesize with a
> > conservative default, to avoid initialization ordering issues.
> > EXEC_PAGESIZE is supposed to be largest supported page size.
>
> This was committed without addressing the comment above.

yes, I also didn't expect this to get pushed until we come to an agreement here.

On topic: I understand that this must have been done this way because
of potential initialization order issues (and the mail I linked also
makes this guess). The question is, is that (working around
initialization order issues) actually required, or is that a leftover
from something that's no longer relevant (or perhaps never was)?
Things seem to still work with this patch on aarch64-gnu for me, both
in SHARED and !SHARED, though I obviously didn't test every potential
codepath.

I was hoping that some broader testing, such as running the testsuite
on CI on existing ports, could answer that question comprehensively --
though now I realize that since this patch leaves the initialization
as-is when EXEC_PAGESIZE is defined (i.e. everywhere but on
aarch64-gnu), CI wouldn't catch any issues that removing it would
cause.

We could define EXEC_PAGESIZE to some conservative value on
aarch64-gnu too, if it turns out that this little workaround is really
required. But it seems cleaner to make sure we don't need to, as
Roland's email suggests, and introducing a new port that doesn't have
a fixed page size (and doesn't come with an EXEC_PAGESIZE value
already defined in kernel headers) seems to be a good opportunity to
do that. That's my reasoning here.

Sergey



[PATCH v2 12/20] mach: Declare the new thread_set_self_state () trap

2024-03-23 Thread Sergey Bugaev
This is a new Mach trap for setting the state of the current thread, as
if with thread_set_state () RPC.  The trap has been added to GNU Mach as
a part of the AArch64 port, to make it possible to implement sigreturn
in glibc; however, the trap itself is fully arch-independent.

There does not seem to be an easy way to feature-test, in a header, for
existence of traps in the Mach version being built against.  Instead,
just declare the trap prototype unconditionally, and don't add an
exported version for now.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/mach/include/mach/mach_traps.h | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/sysdeps/mach/include/mach/mach_traps.h 
b/sysdeps/mach/include/mach/mach_traps.h
index c4334952..a942212c 100644
--- a/sysdeps/mach/include/mach/mach_traps.h
+++ b/sysdeps/mach/include/mach/mach_traps.h
@@ -19,5 +19,12 @@ kern_return_t __thread_switch (mach_port_t new_thread,
 libc_hidden_proto (__thread_switch)
 kern_return_t __evc_wait (unsigned int event);
 libc_hidden_proto (__evc_wait)
+
+/* Set current thread's state, as if with thread_set_state() RPC.
+   This syscall is only really available in recent enough GNU Mach.  */
+extern kern_return_t __thread_set_self_state (int flavor,
+ natural_t *new_state,
+ natural_t new_state_count);
+libc_hidden_proto (__thread_set_self_state)
 #endif
 #endif
-- 
2.44.0




[PATCH v2 10/20] aarch64: Allow building without kernel support for BTI

2024-03-23 Thread Sergey Bugaev
If PROT_BTI is not defined, turn _dl_bti_protect () into a no-op.

We intend to support BTI & PROT_BTI on the Hurd eventually, but we're
not there yet.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/aarch64/dl-bti.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/sysdeps/aarch64/dl-bti.c b/sysdeps/aarch64/dl-bti.c
index fd0d308a..4cf85630 100644
--- a/sysdeps/aarch64/dl-bti.c
+++ b/sysdeps/aarch64/dl-bti.c
@@ -28,6 +28,7 @@
 
 /* Enable BTI protection for MAP.  */
 
+#ifdef PROT_BTI
 void
 _dl_bti_protect (struct link_map *map, int fd)
 {
@@ -59,6 +60,15 @@ _dl_bti_protect (struct link_map *map, int fd)
   }
 }
 
+#else /* PROT_BTI */
+void
+_dl_bti_protect (struct link_map *map, int fd)
+{
+  (void) map;
+  (void) fd;
+}
+#endif
+
 
 static void
 bti_failed (struct link_map *l, const char *program)
-- 
2.44.0




[PATCH v2 15/20] hurd: Implement longjmp for AArch64

2024-03-23 Thread Sergey Bugaev
This is based on the generic AArch64 version, but it additionally
respects and updates the Hurd sigstate.

Signed-off-by: Sergey Bugaev 
---

Same patch as last time.

Something somewhere here should probably be hooked up to the
hurd_userlink mechanism; I haven't looked into that.

 sysdeps/aarch64/htl/tcb-offsets.sym  |   5 +
 sysdeps/mach/hurd/aarch64/Makefile   |  24 +++
 sysdeps/mach/hurd/aarch64/longjmp_chk.S  | 173 +++
 sysdeps/mach/hurd/aarch64/__longjmp.S| 150 
 sysdeps/mach/hurd/aarch64/signal-defines.sym |  10 ++
 5 files changed, 362 insertions(+)
 create mode 100644 sysdeps/aarch64/htl/tcb-offsets.sym
 create mode 100644 sysdeps/mach/hurd/aarch64/Makefile
 create mode 100644 sysdeps/mach/hurd/aarch64/longjmp_chk.S
 create mode 100644 sysdeps/mach/hurd/aarch64/__longjmp.S
 create mode 100644 sysdeps/mach/hurd/aarch64/signal-defines.sym

diff --git a/sysdeps/aarch64/htl/tcb-offsets.sym 
b/sysdeps/aarch64/htl/tcb-offsets.sym
new file mode 100644
index ..56140780
--- /dev/null
+++ b/sysdeps/aarch64/htl/tcb-offsets.sym
@@ -0,0 +1,5 @@
+#include 
+#include 
+#include 
+
+SIGSTATE_OFFSET offsetof (tcbprehead_t, _hurd_sigstate) - sizeof 
(tcbprehead_t)
diff --git a/sysdeps/mach/hurd/aarch64/Makefile 
b/sysdeps/mach/hurd/aarch64/Makefile
new file mode 100644
index ..9210d436
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/Makefile
@@ -0,0 +1,24 @@
+# Copyright (C) 2020-2024 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+ifeq ($(subdir),debug)
+gen-as-const-headers += signal-defines.sym
+endif
+
+ifeq ($(subdir),setjmp)
+gen-as-const-headers += signal-defines.sym
+endif
diff --git a/sysdeps/mach/hurd/aarch64/longjmp_chk.S 
b/sysdeps/mach/hurd/aarch64/longjmp_chk.S
new file mode 100644
index ..90f062df
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/longjmp_chk.S
@@ -0,0 +1,173 @@
+/* Copyright (C) 1997-2024 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define SS_ONSTACK 1
+#define SS_ONSTACK_BIT 0
+
+   .section .rodata.str1.1,"aMS",%progbits,1
+   .type   longjmp_msg,%object
+longjmp_msg:
+   .string "longjmp causes uninitialized stack frame"
+   .size   longjmp_msg, .-longjmp_msg
+   .text
+
+# define CALL_FAIL \
+   adrpx0, longjmp_msg;\
+   add x0, x0, :lo12:longjmp_msg;  \
+   b   HIDDEN_JUMPTARGET(__fortify_fail)   \
+
+/* Jump to the position specified by ENV, causing the
+   setjmp call there to return VAL, or 1 if VAL is 0.
+   void __longjmp (__jmp_buf env, int val).  */
+.text
+ENTRY(longjmp_chk)
+   cfi_def_cfa(x0, 0)
+   cfi_offset(x19, JB_X19<<3)
+   cfi_offset(x20, JB_X20<<3)
+   cfi_offset(x21, JB_X21<<3)
+   cfi_offset(x22, JB_X22<<3)
+   cfi_offset(x23, JB_X23<<3)
+   cfi_offset(x24, JB_X24<<3)
+   cfi_offset(x25, JB_X25<<3)
+   cfi_offset(x26, JB_X26<<3)
+   cfi_offset(x27, JB_X27<<3)
+   cfi_offset(x28, JB_X28<<3)
+   cfi_offset(x29, JB_X29<<3)
+   cfi_offset(x30, JB_LR<<3)
+
+   cfi_offset( d8, JB_D8<<3)
+   cfi_offset( d9, JB_D9<<3)
+   cfi_offset(d10, JB_D10<<3)
+   cfi_offset(d11, JB_D11<<3)
+   cf

[PATCH v2 17/20] hurd: Add an AArch64 signal implementation

2024-03-23 Thread Sergey Bugaev
Signed-off-by: Sergey Bugaev 
---
 sysdeps/mach/hurd/aarch64/Makefile  |   4 +
 sysdeps/mach/hurd/aarch64/bits/sigcontext.h |  96 ++
 sysdeps/mach/hurd/aarch64/exc2signal.c  | 149 +
 sysdeps/mach/hurd/aarch64/intr-msg.h| 123 
 sysdeps/mach/hurd/aarch64/sigreturn.c   | 127 
 sysdeps/mach/hurd/aarch64/trampoline.c  | 325 
 6 files changed, 824 insertions(+)
 create mode 100644 sysdeps/mach/hurd/aarch64/bits/sigcontext.h
 create mode 100644 sysdeps/mach/hurd/aarch64/exc2signal.c
 create mode 100644 sysdeps/mach/hurd/aarch64/intr-msg.h
 create mode 100644 sysdeps/mach/hurd/aarch64/sigreturn.c
 create mode 100644 sysdeps/mach/hurd/aarch64/trampoline.c

diff --git a/sysdeps/mach/hurd/aarch64/Makefile 
b/sysdeps/mach/hurd/aarch64/Makefile
index 9210d436..6cc831d6 100644
--- a/sysdeps/mach/hurd/aarch64/Makefile
+++ b/sysdeps/mach/hurd/aarch64/Makefile
@@ -22,3 +22,7 @@ endif
 ifeq ($(subdir),setjmp)
 gen-as-const-headers += signal-defines.sym
 endif
+
+ifeq ($(subdir),signal)
+CFLAGS-sigreturn.c += -mgeneral-regs-only
+endif
diff --git a/sysdeps/mach/hurd/aarch64/bits/sigcontext.h 
b/sysdeps/mach/hurd/aarch64/bits/sigcontext.h
new file mode 100644
index ..163523fa
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/bits/sigcontext.h
@@ -0,0 +1,96 @@
+/* Machine-dependent signal context structure for GNU Hurd.  AArch64 version.
+   Copyright (C) 1991-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_SIGCONTEXT_H
+#define _BITS_SIGCONTEXT_H 1
+
+#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H
+# error "Never use  directly; include  instead."
+#endif
+
+/* Signal handlers are actually called:
+   void handler (int sig, int code, struct sigcontext *scp);  */
+
+#include 
+#include 
+
+/* State of this thread when the signal was taken.  */
+struct sigcontext
+  {
+/* These first members are machine-independent.  */
+
+int sc_onstack;/* Nonzero if running on sigstack.  */
+__sigset_t sc_mask;/* Blocked signals to restore.  */
+
+/* MiG reply port this thread is using.  */
+unsigned int sc_reply_port;
+
+/* Port this thread is doing an interruptible RPC on.  */
+unsigned int sc_intr_port;
+
+/* Error code associated with this signal (interpreted as `error_t').  */
+int sc_error;
+
+/* Make sure the below members are properly aligned, and not packed
+   together with sc_error -- otherwise the layout won't match that of
+   aarch64_thread_state.  */
+int sc_pad1;
+
+/* All following members are machine-dependent.  The rest of this
+   structure is written to be laid out identically to:
+   {
+struct aarch64_thread_state basic;
+struct aarch64_float_state fpu;
+   }
+   trampoline.c knows this, so it must be changed if this changes.  */
+
+#define sc_aarch64_thread_state sc_x[0] /* Beginning of correspondence.  */
+long sc_x[31];
+long sc_sp;
+long sc_pc;
+long sc_tpidr_el0;
+long sc_cpsr;
+
+#define sc_aarch64_float_state sc_v[0]
+__int128_t sc_v[32];
+long sc_fpsr;
+long sc_fpcr;
+  };
+
+/* Traditional BSD names for some members.  */
+#define sc_fp  sc_x[29]/* Frame pointer.  */
+#define sc_ps  sc_cpsr
+
+
+/* The deprecated sigcode values below are passed as an extra, non-portable
+   argument to regular signal handlers.  You should use SA_SIGINFO handlers
+   instead, which use the standard POSIX signal codes.  */
+
+/* Codes for SIGFPE.  */
+#define FPE_INTOVF_TRAP0x1 /* integer overflow */
+#define FPE_INTDIV_FAULT   0x2 /* integer divide by zero */
+#define FPE_FLTOVF_FAULT   0x3 /* floating overflow */
+#define FPE_FLTDIV_FAULT   0x4 /* floating divide by zero */
+#define FPE_FLTUND_FAULT   0x5 /* floating underflow */
+#define FPE_SUBRNG_FAULT   0x7 /* BOUNDS instruction failed */
+#define FPE_FLTDNR_FAULT   0x8 /* denormalized operand */
+#define FPE_FLTINX_FAULT   0x9 /* floating loss of precision */
+#define FPE_EMERR_FAULT0xa /* mysterious emulation error 33 */
+#define FPE_EMBND_FAULT0xb /* emulation BOUNDS instruction 
failed */
+
+#en

[PATCH v2 04/20] hurd: Disable Prefer_MAP_32BIT_EXEC on non-x86_64 for now

2024-03-23 Thread Sergey Bugaev
While we could support it on any architecture, the tunable is currently
only defined on x86_64.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/mach/hurd/dl-sysdep.c | 2 +-
 sysdeps/mach/hurd/mmap.c  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c
index 43129a1e..6ba00e41 100644
--- a/sysdeps/mach/hurd/dl-sysdep.c
+++ b/sysdeps/mach/hurd/dl-sysdep.c
@@ -457,7 +457,7 @@ __mmap (void *addr, size_t len, int prot, int flags, int 
fd, off_t offset)
   if (prot & PROT_EXEC)
 vmprot |= VM_PROT_EXECUTE;
 
-#ifdef __LP64__
+#ifdef __x86_64__
   if ((addr == NULL) && (prot & PROT_EXEC)
   && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC))
 flags |= MAP_32BIT;
diff --git a/sysdeps/mach/hurd/mmap.c b/sysdeps/mach/hurd/mmap.c
index 7b945610..30e369f0 100644
--- a/sysdeps/mach/hurd/mmap.c
+++ b/sysdeps/mach/hurd/mmap.c
@@ -60,7 +60,7 @@ __mmap (void *addr, size_t len, int prot, int flags, int fd, 
off_t offset)
   copy = ! (flags & MAP_SHARED);
   anywhere = ! (flags & MAP_FIXED);
 
-#ifdef __LP64__
+#ifdef __x86_64__
   if ((addr == NULL) && (prot & PROT_EXEC)
   && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC))
 flags |= MAP_32BIT;
-- 
2.44.0




[PATCH v2 13/20] hurd: Add a basic AArch64 port

2024-03-23 Thread Sergey Bugaev
The following commits will add TLS, HTL, and the signal bits.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/mach/hurd/aarch64/Implies|  3 ++
 sysdeps/mach/hurd/aarch64/longjmp-ts.c   | 49 ++
 sysdeps/mach/hurd/aarch64/shlib-versions |  2 +
 sysdeps/mach/hurd/aarch64/static-start.S | 52 
 sysdeps/mach/hurd/aarch64/vm_param.h | 24 +++
 5 files changed, 130 insertions(+)
 create mode 100644 sysdeps/mach/hurd/aarch64/Implies
 create mode 100644 sysdeps/mach/hurd/aarch64/longjmp-ts.c
 create mode 100644 sysdeps/mach/hurd/aarch64/shlib-versions
 create mode 100644 sysdeps/mach/hurd/aarch64/static-start.S
 create mode 100644 sysdeps/mach/hurd/aarch64/vm_param.h

diff --git a/sysdeps/mach/hurd/aarch64/Implies 
b/sysdeps/mach/hurd/aarch64/Implies
new file mode 100644
index ..02af165f
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/Implies
@@ -0,0 +1,3 @@
+mach/hurd/htl
+aarch64/htl
+mach/hurd/aarch64/htl
diff --git a/sysdeps/mach/hurd/aarch64/longjmp-ts.c 
b/sysdeps/mach/hurd/aarch64/longjmp-ts.c
new file mode 100644
index ..2fcb7493
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/longjmp-ts.c
@@ -0,0 +1,49 @@
+/* Perform a `longjmp' on a Mach thread_state.  AArch64 version.
+   Copyright (C) 1991-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include 
+#include 
+#include 
+
+
+/* Set up STATE to do the equivalent of `longjmp (ENV, VAL);'.  */
+
+void
+_hurd_longjmp_thread_state (void *state, jmp_buf env, int val)
+{
+  struct aarch64_thread_state *ts = state;
+
+  ts->x[19] = env[0].__jmpbuf[JB_X19];
+  ts->x[20] = env[0].__jmpbuf[JB_X20];
+  ts->x[21] = env[0].__jmpbuf[JB_X21];
+  ts->x[22] = env[0].__jmpbuf[JB_X22];
+  ts->x[23] = env[0].__jmpbuf[JB_X23];
+  ts->x[24] = env[0].__jmpbuf[JB_X24];
+  ts->x[25] = env[0].__jmpbuf[JB_X25];
+  ts->x[26] = env[0].__jmpbuf[JB_X26];
+  ts->x[27] = env[0].__jmpbuf[JB_X27];
+  ts->x[28] = env[0].__jmpbuf[JB_X28];
+  ts->x[29] = env[0].__jmpbuf[JB_X29];
+
+  /* XXX: We're ignoring all the d[] (SIMD) registers.
+ Is that fine?  */
+
+  ts->pc = PTR_DEMANGLE (env[0].__jmpbuf[JB_LR]);
+  ts->sp = _jmpbuf_sp (env[0].__jmpbuf);
+  ts->x[0] = val ?: 1;
+}
diff --git a/sysdeps/mach/hurd/aarch64/shlib-versions 
b/sysdeps/mach/hurd/aarch64/shlib-versions
new file mode 100644
index ..b9e7c2cb
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/shlib-versions
@@ -0,0 +1,2 @@
+DEFAULTGLIBC_2.40
+ld=ld-aarch64.so.1
diff --git a/sysdeps/mach/hurd/aarch64/static-start.S 
b/sysdeps/mach/hurd/aarch64/static-start.S
new file mode 100644
index ..e09865c4
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/static-start.S
@@ -0,0 +1,52 @@
+/* Startup code for statically linked Hurd/AArch64 binaries.
+   Copyright (C) 1998-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include 
+
+/* This is the actual entry point for statically linked aarch64-gnu 
executables,
+   the very first code to run in a process.  */
+
+   .text
+ENTRY(_start)
+   /* Set up the initial stack frame.  */
+   cfi_undefined (x30)
+   mov x29, #0
+   mov x30, #0
+
+   /* Pre-fill GOT entries for select ifunc routines that may get
+  called during _hurd_stack_setup () with baseline implementations.  */
+   adrpx1, __memcpy_generic
+   add x1, x1, #:lo12:__memcpy_generic
+   adrpx0, :got:memcpy
+   str x1, [x0, :got_lo12:memcpy]
+
+   adrp 

[PATCH v2 18/20] htl: Implement some support for TLS_DTV_AT_TP

2024-03-23 Thread Sergey Bugaev
Signed-off-by: Sergey Bugaev 
---
 htl/pt-create.c |  2 ++
 sysdeps/htl/dl-thread_gscope_wait.c | 16 ++--
 sysdeps/mach/hurd/htl/pt-sysdep.c   |  9 +
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/htl/pt-create.c b/htl/pt-create.c
index fac61f1b..8a735d99 100644
--- a/htl/pt-create.c
+++ b/htl/pt-create.c
@@ -177,7 +177,9 @@ __pthread_create_internal (struct __pthread **thread,
   err = ENOMEM;
   goto failed_thread_tls_alloc;
 }
+#if TLS_TCB_AT_TP
   pthread->tcb->tcb = pthread->tcb;
+#endif
 
   /* And initialize the rest of the machine context.  This may include
  additional machine- and system-specific initializations that
diff --git a/sysdeps/htl/dl-thread_gscope_wait.c 
b/sysdeps/htl/dl-thread_gscope_wait.c
index 90a9a798..ee0a3165 100644
--- a/sysdeps/htl/dl-thread_gscope_wait.c
+++ b/sysdeps/htl/dl-thread_gscope_wait.c
@@ -20,6 +20,18 @@
 #include 
 #include 
 
+static inline int *
+thread_gscope_flag (struct __pthread *t)
+{
+#if TLS_TCB_AT_TP
+  return >tcb->gscope_flag;
+#elif TLS_DTV_AT_TP
+  return &((tcbprehead_t *) t->tcb - 1)->gscope_flag;
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+}
+
 void
 __thread_gscope_wait (void)
 {
@@ -33,10 +45,10 @@ __thread_gscope_wait (void)
   for (i = 0; i < GL (dl_pthread_num_threads); ++i)
 {
   t = GL (dl_pthread_threads[i]);
-  if (t == NULL || t->tcb->gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+  if (t == NULL || *thread_gscope_flag (t) == THREAD_GSCOPE_FLAG_UNUSED)
 continue;
 
-  gscope_flagp = >tcb->gscope_flag;
+  gscope_flagp = thread_gscope_flag (t);
 
   /* We have to wait until this thread is done with the global
  scope.  First tell the thread that we are waiting and
diff --git a/sysdeps/mach/hurd/htl/pt-sysdep.c 
b/sysdeps/mach/hurd/htl/pt-sysdep.c
index 270e7753..5372cbf7 100644
--- a/sysdeps/mach/hurd/htl/pt-sysdep.c
+++ b/sysdeps/mach/hurd/htl/pt-sysdep.c
@@ -100,7 +100,16 @@ _init_routine (void *stack)
  to the new stack.  Pretend it wasn't allocated so that it remains
  valid if the main thread terminates.  */
   thread->stack = 0;
+#if TLS_TCB_AT_TP
   thread->tcb = THREAD_SELF;
+#elif TLS_DTV_AT_TP
+  /* Assuming THREAD_SELF is implemented as subtracting TLS_PRE_TCB_SIZE
+ from the value of a thread pointer regsiter, this should optimize
+ down to simply reading that register.  */
+  thread->tcb = (tcbhead_t *) (((char *) THREAD_SELF) + TLS_PRE_TCB_SIZE);
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
 
 #ifndef PAGESIZE
   __pthread_default_attr.__guardsize = __vm_page_size;
-- 
2.44.0




[PATCH v2 08/20] aarch64: Add dl-procinfo

2024-03-23 Thread Sergey Bugaev
This is based on the Linux version, but doesn't define
GLRO(dl_aarch64_cap_flags) and implement _dl_hwcap_string (which seems
unused anyway) based on Linux HWCAP bit values.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/aarch64/dl-procinfo.c | 59 +++
 sysdeps/aarch64/dl-procinfo.h | 38 ++
 2 files changed, 97 insertions(+)
 create mode 100644 sysdeps/aarch64/dl-procinfo.c
 create mode 100644 sysdeps/aarch64/dl-procinfo.h

diff --git a/sysdeps/aarch64/dl-procinfo.c b/sysdeps/aarch64/dl-procinfo.c
new file mode 100644
index ..5a51edbc
--- /dev/null
+++ b/sysdeps/aarch64/dl-procinfo.c
@@ -0,0 +1,59 @@
+/* Data for AArch64 version of processor capability information.
+   Copyright (C) 2017-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* If anything should be added here check whether the size of each string
+   is still ok with the given array size.
+
+   All the #ifdefs in the definitions are quite irritating but
+   necessary if we want to avoid duplicating the information.  There
+   are three different modes:
+
+   - PROCINFO_DECL is defined.  This means we are only interested in
+ declarations.
+
+   - PROCINFO_DECL is not defined:
+
+ + if SHARED is defined the file is included in an array
+   initializer.  The .element = { ... } syntax is needed.
+
+ + if SHARED is not defined a normal array initialization is
+   needed.
+  */
+
+#ifndef PROCINFO_CLASS
+# define PROCINFO_CLASS
+#endif
+
+#if !IS_IN (ldconfig)
+# if !defined PROCINFO_DECL && defined SHARED
+  ._dl_aarch64_cpu_features
+# else
+PROCINFO_CLASS struct cpu_features _dl_aarch64_cpu_features
+# endif
+# ifndef PROCINFO_DECL
+= { }
+# endif
+# if !defined SHARED || defined PROCINFO_DECL
+;
+# else
+,
+# endif
+#endif
+
+#undef PROCINFO_DECL
+#undef PROCINFO_CLASS
diff --git a/sysdeps/aarch64/dl-procinfo.h b/sysdeps/aarch64/dl-procinfo.h
new file mode 100644
index ..176de5cd
--- /dev/null
+++ b/sysdeps/aarch64/dl-procinfo.h
@@ -0,0 +1,38 @@
+/* Processor capability information handling macros - aarch64 version.
+   Copyright (C) 2017-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_PROCINFO_H
+#define _DL_PROCINFO_H 1
+
+#include 
+#include 
+#include 
+#include 
+
+/* We cannot provide a general printing function.  */
+#define _dl_procinfo(type, word) -1
+
+/* No additional library search paths.  */
+#define HWCAP_IMPORTANT HWCAP_ATOMICS
+
+/* There're no platforms to filter out.  */
+#define _DL_HWCAP_PLATFORM 0
+
+#define _dl_string_platform(str) (-1)
+
+#endif /* dl-procinfo.h */
-- 
2.44.0




[PATCH v2 11/20] mach: Add a basic AArch64 port

2024-03-23 Thread Sergey Bugaev
This doesn't add any of the Hurd- or HTL-specific bits yet.

Signed-off-by: Sergey Bugaev 
---
 mach/Makefile  |   1 +
 sysdeps/mach/aarch64/bits/mach/param.h |  24 ++
 sysdeps/mach/aarch64/cpu-features.c| 109 +
 sysdeps/mach/aarch64/sys/ucontext.h|  73 +
 sysdeps/mach/aarch64/sysdep.h  |  52 
 sysdeps/mach/aarch64/thread_state.h|  49 +++
 sysdeps/mach/configure |   1 +
 sysdeps/mach/configure.ac  |   1 +
 8 files changed, 310 insertions(+)
 create mode 100644 sysdeps/mach/aarch64/bits/mach/param.h
 create mode 100644 sysdeps/mach/aarch64/cpu-features.c
 create mode 100644 sysdeps/mach/aarch64/sys/ucontext.h
 create mode 100644 sysdeps/mach/aarch64/sysdep.h
 create mode 100644 sysdeps/mach/aarch64/thread_state.h

diff --git a/mach/Makefile b/mach/Makefile
index 0ea3b3c1..92394951 100644
--- a/mach/Makefile
+++ b/mach/Makefile
@@ -56,6 +56,7 @@ generated =
 
 # Avoid ssp before TLS is initialized.
 CFLAGS-mach_init.o = $(no-stack-protector)
+CFLAGS-RPC_aarch64_get_hwcaps.o = $(no-stack-protector)
 CFLAGS-RPC_vm_statistics.o = $(no-stack-protector)
 CFLAGS-RPC_vm_map.o = $(no-stack-protector)
 CFLAGS-RPC_vm_protect.o = $(no-stack-protector)
diff --git a/sysdeps/mach/aarch64/bits/mach/param.h 
b/sysdeps/mach/aarch64/bits/mach/param.h
new file mode 100644
index ..4f7b76ed
--- /dev/null
+++ b/sysdeps/mach/aarch64/bits/mach/param.h
@@ -0,0 +1,24 @@
+/* Old-style Unix parameters and limits.  aarch64 Mach version.
+   Copyright (C) 1993-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _SYS_PARAM_H
+# error "Never use  directly; include  
instead."
+#endif
+
+/* There is no EXEC_PAGESIZE.  Use vm_page_size or getpagesize ()
+   or sysconf (_SC_PAGESIZE) instead.  */
diff --git a/sysdeps/mach/aarch64/cpu-features.c 
b/sysdeps/mach/aarch64/cpu-features.c
new file mode 100644
index ..1d1f5201
--- /dev/null
+++ b/sysdeps/mach/aarch64/cpu-features.c
@@ -0,0 +1,109 @@
+/* Initialize CPU feature data.  Mach AArch64 version.
+   This file is part of the GNU C Library.
+   Copyright (C) 2017-2024 Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DCZID_DZP_MASK (1 << 4)
+#define DCZID_BS_MASK (0xf)
+
+/* The maximal set of permitted tags that the MTE random tag generation
+   instruction may use.  We exclude tag 0 because a) we want to reserve
+   that for the libc heap structures and b) because it makes it easier
+   to see when pointer have been correctly tagged.  */
+#define MTE_ALLOWED_TAGS (0xfffe << PR_MTE_TAG_SHIFT)
+
+struct cpu_list
+{
+  const char *name;
+  size_t len;
+  uint64_t midr;
+};
+
+static const struct cpu_list cpu_list[] =
+{
+#define CPU_LIST_ENTRY(__str, __num) { __str, sizeof (__str) - 1, __num }
+  CPU_LIST_ENTRY ("thunderxt88",0x430F0A10),
+  CPU_LIST_ENTRY ("thunderx2t99",   0x431F0AF0),
+  CPU_LIST_ENTRY ("thunderx2t99p1", 0x420F5160),
+  CPU_LIST_ENTRY ("ares",   0x411FD0C0),
+  CPU_LIST_ENTRY ("emag",   0x503F0001),
+  CPU_LIST_ENTRY ("kunpeng920", 0x481FD010),
+  CPU_LIST_ENTRY ("a64fx",  0x460F0010),
+  CPU_LIST_ENTRY ("generic",0x0),
+};
+
+static uint64_t
+get_midr_from_mcpu (const struct tunable_str_t *mcpu)
+{
+  for (int i = 0; i < array_length (cpu_list); i++)
+if (tunable_strcmp (mcpu, cpu_list[i].name, 

[PATCH v2 16/20] Add FPE_FLTIDO

2024-03-23 Thread Sergey Bugaev
This is a new si_code value for the SIGFPE signal that has been added
to FreeBSD, and is also going to be used on the Hurd.

Signed-off-by: Sergey Bugaev 
---

This makes sense, right?

We should probably define more codes still (see exception2signal in the
next patch).

 bits/siginfo-consts.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/bits/siginfo-consts.h b/bits/siginfo-consts.h
index 4eef775e..362a06a6 100644
--- a/bits/siginfo-consts.h
+++ b/bits/siginfo-consts.h
@@ -75,8 +75,10 @@ enum
 #  define FPE_FLTRES   FPE_FLTRES
   FPE_FLTINV,  /* Floating point invalid operation.  */
 #  define FPE_FLTINV   FPE_FLTINV
-  FPE_FLTSUB   /* Subscript out of range.  */
+  FPE_FLTSUB,  /* Subscript out of range.  */
 #  define FPE_FLTSUB   FPE_FLTSUB
+  FPE_FLTIDO   /* Input denormal operation.  */
+#  define FPE_FLTIDO   FPE_FLTIDO
 };
 
 /* `si_code' values for SIGSEGV signal.  */
-- 
2.44.0




[PATCH v2 19/20] htl: Add an AArch64 implementation

2024-03-23 Thread Sergey Bugaev
Signed-off-by: Sergey Bugaev 
---
 sysdeps/aarch64/htl/Makefile | 20 ++
 sysdeps/aarch64/htl/bits/pthreadtypes-arch.h | 36 ++
 sysdeps/aarch64/htl/machine-sp.h | 29 
 sysdeps/aarch64/htl/pt-machdep.h | 28 
 sysdeps/mach/hurd/aarch64/htl/pt-machdep.c   | 55 ++
 sysdeps/mach/hurd/aarch64/htl/pt-setup.c | 76 
 6 files changed, 244 insertions(+)
 create mode 100644 sysdeps/aarch64/htl/Makefile
 create mode 100644 sysdeps/aarch64/htl/bits/pthreadtypes-arch.h
 create mode 100644 sysdeps/aarch64/htl/machine-sp.h
 create mode 100644 sysdeps/aarch64/htl/pt-machdep.h
 create mode 100644 sysdeps/mach/hurd/aarch64/htl/pt-machdep.c
 create mode 100644 sysdeps/mach/hurd/aarch64/htl/pt-setup.c

diff --git a/sysdeps/aarch64/htl/Makefile b/sysdeps/aarch64/htl/Makefile
new file mode 100644
index ..686b843d
--- /dev/null
+++ b/sysdeps/aarch64/htl/Makefile
@@ -0,0 +1,20 @@
+# Copyright (C) 2020-2024 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/aarch64/htl/bits/pthreadtypes-arch.h 
b/sysdeps/aarch64/htl/bits/pthreadtypes-arch.h
new file mode 100644
index ..9ee1568e
--- /dev/null
+++ b/sysdeps/aarch64/htl/bits/pthreadtypes-arch.h
@@ -0,0 +1,36 @@
+/* Machine-specific pthread type layouts.  Hurd AArch64 version.
+   Copyright (C) 2002-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_PTHREADTYPES_ARCH_H
+#define _BITS_PTHREADTYPES_ARCH_H  1
+
+#define __SIZEOF_PTHREAD_MUTEX_T 32
+#define __SIZEOF_PTHREAD_ATTR_T 48
+#define __SIZEOF_PTHREAD_RWLOCK_T 48
+#define __SIZEOF_PTHREAD_BARRIER_T 40
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 16
+#define __SIZEOF_PTHREAD_COND_T 40
+#define __SIZEOF_PTHREAD_CONDATTR_T 8
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 4
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#define __SIZEOF_PTHREAD_ONCE_T 8
+
+#define __LOCK_ALIGNMENT
+#define __ONCE_ALIGNMENT
+
+#endif /* bits/pthreadtypes.h */
diff --git a/sysdeps/aarch64/htl/machine-sp.h b/sysdeps/aarch64/htl/machine-sp.h
new file mode 100644
index ..b21331a0
--- /dev/null
+++ b/sysdeps/aarch64/htl/machine-sp.h
@@ -0,0 +1,29 @@
+/* Machine-specific function to return the stack pointer.  AArch64 version.
+   Copyright (C) 1994-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library;  if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _MACHINE_SP_H
+#define _MACHINE_SP_H
+
+/* Return the current stack pointer.  */
+
+#define __thread_stack_pointer() ({
\
+  register uintptr_t __sp__ asm("sp"); 
\
+  __sp__;  
\
+})
+
+#endif /* machine-sp.h */
diff --

[PATCH v2 09/20] aarch64: Move saving user entry into _dl_start_user

2024-03-23 Thread Sergey Bugaev
In the Hurd ports, _dl_start () does not return the normal way; instead,
_dl_sysdep_start () jumps to _dl_start_user directly using the RETURN_TO
macro.  Unlike in the i386 and x86_64 ports, the instruction that was
saving the returned user entry into a different register (to avoid it
getting clobbered by the _dl_init () call) was not marked as a part of
_dl_start_user, causing it to be skipped when jumping to _dl_start_user
using RETURN_TO, and control subsequently getting transferred to a
random address left in x21.

This should not make any difference for Linux ports, other than the
_dl_start_user label pointing to an earlier instruction.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/aarch64/dl-start.S | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sysdeps/aarch64/dl-start.S b/sysdeps/aarch64/dl-start.S
index d645484e..e35431ca 100644
--- a/sysdeps/aarch64/dl-start.S
+++ b/sysdeps/aarch64/dl-start.S
@@ -29,10 +29,10 @@ ENTRY (_start)
PTR_ARG (0)
bl  _dl_start
/* Returns user entry point in x0.  */
-   mov PTR_REG (21), PTR_REG (0)
 .globl _dl_start_user
 .type _dl_start_user, %function
 _dl_start_user:
+   mov PTR_REG (21), PTR_REG (0)
/* Get argc.  */
ldr PTR_REG (1), [sp]
/* Get argv.  */
-- 
2.44.0




[PATCH v2 20/20] hurd: Add expected aarch64-gnu abistlists

2024-03-23 Thread Sergey Bugaev
Signed-off-by: Sergey Bugaev 
---

We obviously didn't make it into the 2.39 timeframe, so now tentatively
targeting 2.40.

 sysdeps/mach/hurd/aarch64/ld.abilist  |   18 +
 .../mach/hurd/aarch64/libBrokenLocale.abilist |1 +
 sysdeps/mach/hurd/aarch64/libanl.abilist  |4 +
 sysdeps/mach/hurd/aarch64/libc.abilist| 2193 +
 .../hurd/aarch64/libc_malloc_debug.abilist|   26 +
 sysdeps/mach/hurd/aarch64/libdl.abilist   |0
 sysdeps/mach/hurd/aarch64/libm.abilist| 1030 
 sysdeps/mach/hurd/aarch64/libmvec.abilist |   75 +
 sysdeps/mach/hurd/aarch64/libpthread.abilist  |  165 ++
 sysdeps/mach/hurd/aarch64/libresolv.abilist   |   55 +
 sysdeps/mach/hurd/aarch64/librt.abilist   |   33 +
 11 files changed, 3600 insertions(+)
 create mode 100644 sysdeps/mach/hurd/aarch64/ld.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libBrokenLocale.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libanl.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libc.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libc_malloc_debug.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libdl.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libm.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libmvec.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libpthread.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/libresolv.abilist
 create mode 100644 sysdeps/mach/hurd/aarch64/librt.abilist

diff --git a/sysdeps/mach/hurd/aarch64/ld.abilist 
b/sysdeps/mach/hurd/aarch64/ld.abilist
new file mode 100644
index ..ba01b289
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/ld.abilist
@@ -0,0 +1,18 @@
+GLIBC_2.40 __close F
+GLIBC_2.40 __errno_location F
+GLIBC_2.40 __getpid F
+GLIBC_2.40 __libc_stack_end D 0x8
+GLIBC_2.40 __mmap F
+GLIBC_2.40 __open F
+GLIBC_2.40 __open64 F
+GLIBC_2.40 __pread64 F
+GLIBC_2.40 __read F
+GLIBC_2.40 __sbrk F
+GLIBC_2.40 __stack_chk_guard D 0x8
+GLIBC_2.40 __tls_get_addr F
+GLIBC_2.40 __write F
+GLIBC_2.40 __writev F
+GLIBC_2.40 _dl_mcount F
+GLIBC_2.40 _hurd_intr_rpc_mach_msg F
+GLIBC_2.40 _r_debug D 0x28
+GLIBC_2.40 abort F
diff --git a/sysdeps/mach/hurd/aarch64/libBrokenLocale.abilist 
b/sysdeps/mach/hurd/aarch64/libBrokenLocale.abilist
new file mode 100644
index ..f54dcd1b
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/libBrokenLocale.abilist
@@ -0,0 +1 @@
+GLIBC_2.40 __ctype_get_mb_cur_max F
diff --git a/sysdeps/mach/hurd/aarch64/libanl.abilist 
b/sysdeps/mach/hurd/aarch64/libanl.abilist
new file mode 100644
index ..47ee5ca3
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/libanl.abilist
@@ -0,0 +1,4 @@
+GLIBC_2.40 gai_cancel F
+GLIBC_2.40 gai_error F
+GLIBC_2.40 gai_suspend F
+GLIBC_2.40 getaddrinfo_a F
diff --git a/sysdeps/mach/hurd/aarch64/libc.abilist 
b/sysdeps/mach/hurd/aarch64/libc.abilist
new file mode 100644
index ..3e16e997
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/libc.abilist
@@ -0,0 +1,2193 @@
+GLIBC_2.40 _Exit F
+GLIBC_2.40 _Fork F
+GLIBC_2.40 _IO_2_1_stderr_ D 0xe0
+GLIBC_2.40 _IO_2_1_stdin_ D 0xe0
+GLIBC_2.40 _IO_2_1_stdout_ D 0xe0
+GLIBC_2.40 _IO_adjust_column F
+GLIBC_2.40 _IO_adjust_wcolumn F
+GLIBC_2.40 _IO_default_doallocate F
+GLIBC_2.40 _IO_default_finish F
+GLIBC_2.40 _IO_default_pbackfail F
+GLIBC_2.40 _IO_default_uflow F
+GLIBC_2.40 _IO_default_xsgetn F
+GLIBC_2.40 _IO_default_xsputn F
+GLIBC_2.40 _IO_do_write F
+GLIBC_2.40 _IO_doallocbuf F
+GLIBC_2.40 _IO_fclose F
+GLIBC_2.40 _IO_fdopen F
+GLIBC_2.40 _IO_feof F
+GLIBC_2.40 _IO_ferror F
+GLIBC_2.40 _IO_fflush F
+GLIBC_2.40 _IO_fgetpos F
+GLIBC_2.40 _IO_fgetpos64 F
+GLIBC_2.40 _IO_fgets F
+GLIBC_2.40 _IO_file_attach F
+GLIBC_2.40 _IO_file_close F
+GLIBC_2.40 _IO_file_close_it F
+GLIBC_2.40 _IO_file_doallocate F
+GLIBC_2.40 _IO_file_finish F
+GLIBC_2.40 _IO_file_fopen F
+GLIBC_2.40 _IO_file_init F
+GLIBC_2.40 _IO_file_jumps D 0xa8
+GLIBC_2.40 _IO_file_open F
+GLIBC_2.40 _IO_file_overflow F
+GLIBC_2.40 _IO_file_read F
+GLIBC_2.40 _IO_file_seek F
+GLIBC_2.40 _IO_file_seekoff F
+GLIBC_2.40 _IO_file_setbuf F
+GLIBC_2.40 _IO_file_stat F
+GLIBC_2.40 _IO_file_sync F
+GLIBC_2.40 _IO_file_underflow F
+GLIBC_2.40 _IO_file_write F
+GLIBC_2.40 _IO_file_xsputn F
+GLIBC_2.40 _IO_flockfile F
+GLIBC_2.40 _IO_flush_all F
+GLIBC_2.40 _IO_flush_all_linebuffered F
+GLIBC_2.40 _IO_fopen F
+GLIBC_2.40 _IO_fprintf F
+GLIBC_2.40 _IO_fputs F
+GLIBC_2.40 _IO_fread F
+GLIBC_2.40 _IO_free_backup_area F
+GLIBC_2.40 _IO_free_wbackup_area F
+GLIBC_2.40 _IO_fsetpos F
+GLIBC_2.40 _IO_fsetpos64 F
+GLIBC_2.40 _IO_ftell F
+GLIBC_2.40 _IO_ftrylockfile F
+GLIBC_2.40 _IO_funlockfile F
+GLIBC_2.40 _IO_fwrite F
+GLIBC_2.40 _IO_getc F
+GLIBC_2.40 _IO_getline F
+GLIBC_2.40 _IO_getline_info F
+GLIBC_2.40 _IO_gets F
+GLIBC_2.40 _IO_init F
+GLIBC_2.40 _IO_init_marker F
+GLIBC_2.40 _IO_init_wmarker F
+GLIBC_2.40 _IO_iter_begin F
+GLIBC_2.40 _IO_iter_end F
+GLIBC_2.40 _IO_iter_file F
+GLIBC_2.40 _IO_iter_next F
+GLIBC_2.40 _IO_least_wmarker F

[PATCH v2 14/20] hurd: Implement TLS on AArch64

2024-03-23 Thread Sergey Bugaev
This is using TLS_DTV_AT_TP, aka "Variant I" layout. tpidr_el0, which is
both readable and writable from userspace, is used as the thread pointer.

We store our Hurd-specific data (sigstate and reply port) *before* the
TCB head, in a tcbprehead_t structure. This tcbprehead_t structure is
also what THREAD_SELF, THREAD_GETMEM, and THREAD_SETMEM macros access.

Signed-off-by: Sergey Bugaev 
---
 .../mach/hurd/aarch64/dl-tls-initialized.c|  19 ++
 sysdeps/mach/hurd/aarch64/tls.h   | 206 ++
 2 files changed, 225 insertions(+)
 create mode 100644 sysdeps/mach/hurd/aarch64/dl-tls-initialized.c
 create mode 100644 sysdeps/mach/hurd/aarch64/tls.h

diff --git a/sysdeps/mach/hurd/aarch64/dl-tls-initialized.c 
b/sysdeps/mach/hurd/aarch64/dl-tls-initialized.c
new file mode 100644
index ..9beafec3
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/dl-tls-initialized.c
@@ -0,0 +1,19 @@
+/* Determine whether TLS is initialized, for AArch64/Hurd.
+   Copyright (C) 1995-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* Nothing here, it's all handled in tls.h */
diff --git a/sysdeps/mach/hurd/aarch64/tls.h b/sysdeps/mach/hurd/aarch64/tls.h
new file mode 100644
index ..712134e1
--- /dev/null
+++ b/sysdeps/mach/hurd/aarch64/tls.h
@@ -0,0 +1,206 @@
+/* Copyright (C) 2005-2024 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _AARCH64_TLS_H
+#define _AARCH64_TLS_H 1
+
+/* Some things really need not be machine-dependent.  */
+#include 
+
+#include 
+
+#ifndef __ASSEMBLER__
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+#endif /* __ASSEMBLER__ */
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include 
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP 1
+# define TLS_TCB_AT_TP 0
+
+typedef struct
+{
+  /* Used by the exception handling implementation in the dynamic loader.  */
+  struct rtld_catch *rtld_catch;
+
+  struct hurd_sigstate *_hurd_sigstate;
+  mach_port_t reply_port;  /* This thread's reply port.  */
+
+  int gscope_flag;
+} tcbprehead_t;
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+# define TLS_PRE_TCB_SIZE  sizeof (tcbprehead_t)
+
+# define TCB_ALIGNMENT 64
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV() = (dtv))
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) __builtin_thread_pointer ())->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+ ((tcbprehead_t *)__builtin_thread_pointer () - 1)
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) \
+  ((descr)->member)
+
+/* Write member of the thread descriptor directly.  */
+# define THREAD_SETMEM(descr, member, value) \
+  ((descr)->member = (value))
+
+/* Return the TCB address of a thread given its state.
+   Note: this is expensive.  */
+static inline tcbprehead_t * __attribute__ ((unused))
+THREAD_TCB (thread_t thread,
+struct machine_thread_all_state *all_state)
+{
+  int ok;
+  const struct aarch64_thread_state *state;
+  tcbhead_t *tcb;
+
+  ok = machine_get_basic_state (thread, all_state);
+  assert (ok);
+  state = &((struct machine_thread_all_state *) all

[PATCH v2 07/20] aarch64: Move pointer_guard.h out of sysdeps/unix/sysv/linux

2024-03-23 Thread Sergey Bugaev
Nothing about this is Linux-specific.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/{unix/sysv/linux => }/aarch64/pointer_guard.h | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename sysdeps/{unix/sysv/linux => }/aarch64/pointer_guard.h (100%)

diff --git a/sysdeps/unix/sysv/linux/aarch64/pointer_guard.h 
b/sysdeps/aarch64/pointer_guard.h
similarity index 100%
rename from sysdeps/unix/sysv/linux/aarch64/pointer_guard.h
rename to sysdeps/aarch64/pointer_guard.h
-- 
2.44.0




[PATCH v2 02/20] hurd: Stop relying on VM_MAX_ADDRESS

2024-03-23 Thread Sergey Bugaev
We'd like to avoid committing to a specific size of virtual address
space (i.e. the value of VM_AARCH64_T0SZ) on AArch64.  While the current
version of GNU Mach still exports VM_MAX_ADDRESS for compatibility, we
should try to avoid relying on it when we can.  This piece of logic in
_hurdsig_getenv () doesn't actually care about the size of user-
accessible virtual address space, it just wants to preempt faults on any
addresses starting from the value of the P pointer and above.  So, use
(unsigned long int) -1 instead of VM_MAX_ADDRESS.

While at it, change the casts to (unsigned long int) and not just
(long int), since the type of struct hurd_signal_preemptor.{first,last}
is unsigned long int.

Signed-off-by: Sergey Bugaev 
---
 hurd/hurdsig.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 882a0347..8b1928d1 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -1658,8 +1658,8 @@ _hurdsig_getenv (const char *variable)
   while (*ep)
{
  const char *p = *ep;
- _hurdsig_fault_preemptor.first = (long int) p;
- _hurdsig_fault_preemptor.last = VM_MAX_ADDRESS;
+ _hurdsig_fault_preemptor.first = (unsigned long int) p;
+ _hurdsig_fault_preemptor.last = (unsigned long int) -1;
  if (! strncmp (p, variable, len) && p[len] == '=')
{
  size_t valuelen;
@@ -1671,8 +1671,8 @@ _hurdsig_getenv (const char *variable)
memcpy (value, p, valuelen);
  break;
}
- _hurdsig_fault_preemptor.first = (long int) ++ep;
- _hurdsig_fault_preemptor.last = (long int) (ep + 1);
+ _hurdsig_fault_preemptor.first = (unsigned long int) ++ep;
+ _hurdsig_fault_preemptor.last = (unsigned long int) (ep + 1);
}
   _hurdsig_end_catch_fault ();
   return value;
-- 
2.44.0




[PATCH v2 01/20] hurd: Move internal functions to internal header

2024-03-23 Thread Sergey Bugaev
Move _hurd_self_sigstate (), _hurd_critical_section_lock (), and
_hurd_critical_section_unlock () inline implementations (that were
already guarded by #if defined _LIBC) to the internal version of the
header.  While at it, add  to the includes, and use
__LIBC_NO_TLS () unconditionally.

Signed-off-by: Sergey Bugaev 
---

This is the remaining part of the "hurd: Add some missing includes"
patch from v1, redone in a different way, as discussed last time.

The hurd/check-installed-headers-c test seems to pass for me, but please
check on your end too.

 hurd/hurd/signal.h | 87 --
 sysdeps/hurd/include/hurd/signal.h | 78 +++
 2 files changed, 78 insertions(+), 87 deletions(-)

diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h
index 6bc7103b..5d116fb2 100644
--- a/hurd/hurd/signal.h
+++ b/hurd/hurd/signal.h
@@ -40,11 +40,6 @@
 #include /* For `jmp_buf'.  */
 #include 
 struct hurd_signal_preemptor;  /*  */
-#if defined __USE_EXTERN_INLINES && defined _LIBC
-# if IS_IN (libc) || IS_IN (libpthread)
-#  include 
-# endif
-#endif
 
 
 /* Full details of a signal.  */
@@ -157,33 +152,6 @@ extern void _hurd_sigstate_unlock (struct hurd_sigstate 
*ss);
 /* Used by libpthread to remove stale sigstate structures.  */
 extern void _hurd_sigstate_delete (thread_t thread);
 
-#ifndef _HURD_SIGNAL_H_EXTERN_INLINE
-#define _HURD_SIGNAL_H_EXTERN_INLINE __extern_inline
-#endif
-
-#if defined __USE_EXTERN_INLINES && defined _LIBC
-# if IS_IN (libc)
-_HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate *
-_hurd_self_sigstate (void)
-{
-  struct hurd_sigstate *ss = THREAD_GETMEM (THREAD_SELF, _hurd_sigstate);
-  if (__glibc_unlikely (ss == NULL))
-{
-  thread_t self = __mach_thread_self ();
-
-  /* The thread variable is unset; this must be the first time we've
-asked for it.  In this case, the critical section flag cannot
-possible already be set.  Look up our sigstate structure the slow
-way.  */
-  ss = _hurd_thread_sigstate (self);
-  THREAD_SETMEM (THREAD_SELF, _hurd_sigstate, ss);
-  __mach_port_deallocate (__mach_task_self (), self);
-}
-  return ss;
-}
-# endif
-#endif
-
 struct machine_thread_all_state;
 extern mach_port_t
 _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
@@ -215,63 +183,8 @@ extern int _hurd_core_limit;
avoid unexpectingly exposing EINTR to the application.  */
 
 extern void *_hurd_critical_section_lock (void);
-
-#if defined __USE_EXTERN_INLINES && defined _LIBC
-# if IS_IN (libc)
-_HURD_SIGNAL_H_EXTERN_INLINE void *
-_hurd_critical_section_lock (void)
-{
-  struct hurd_sigstate *ss;
-
-#ifdef __LIBC_NO_TLS
-  if (__LIBC_NO_TLS ())
-/* TLS is currently initializing, no need to enter critical section.  */
-return NULL;
-#endif
-
-  ss = _hurd_self_sigstate ();
-
-  if (! __spin_try_lock (>critical_section_lock))
-/* We are already in a critical section, so do nothing.  */
-return NULL;
-
-  /* With the critical section lock held no signal handler will run.
- Return our sigstate pointer; this will be passed to
- _hurd_critical_section_unlock to unlock it.  */
-  return ss;
-}
-# endif
-#endif
-
 extern void _hurd_critical_section_unlock (void *our_lock);
 
-#if defined __USE_EXTERN_INLINES && defined _LIBC
-# if IS_IN (libc)
-_HURD_SIGNAL_H_EXTERN_INLINE void
-_hurd_critical_section_unlock (void *our_lock)
-{
-  if (our_lock == NULL)
-/* The critical section lock was held when we began.  Do nothing.  */
-return;
-  else
-{
-  /* It was us who acquired the critical section lock.  Unlock it.  */
-  struct hurd_sigstate *ss = (struct hurd_sigstate *) our_lock;
-  sigset_t pending;
-  _hurd_sigstate_lock (ss);
-  __spin_unlock (>critical_section_lock);
-  pending = _hurd_sigstate_pending (ss) & ~ss->blocked;
-  _hurd_sigstate_unlock (ss);
-  if (__glibc_unlikely (!__sigisemptyset ()))
-   /* There are unblocked signals pending, which weren't
-  delivered because we were in the critical section.
-  Tell the signal thread to deliver them now.  */
-   __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
-}
-}
-# endif
-#endif
-
 /* Convenient macros for simple uses of critical sections.
These two must be used as a pair at the same C scoping level.  */
 
diff --git a/sysdeps/hurd/include/hurd/signal.h 
b/sysdeps/hurd/include/hurd/signal.h
index 1dc8a1f3..fab8d1b6 100644
--- a/sysdeps/hurd/include/hurd/signal.h
+++ b/sysdeps/hurd/include/hurd/signal.h
@@ -9,6 +9,84 @@ libc_hidden_proto (_hurd_self_sigstate)
 #include_next 
 
 #ifndef _ISOMAC
+
+#if defined __USE_EXTERN_INLINES
+# if IS_IN (libc) || IS_IN (libpthread)
+#  include 
+#  include 
+# endif
+#endif
+
+#ifndef _HURD_SIGNAL_H_EXTERN_INLINE
+#define _HURD_SIGNAL_H_EXTERN_INLINE __extern_inline
+#endif
+
+#if defined __USE_EXTERN_INLIN

[PATCH v2 06/20] htl: Respect GL(dl_stack_flags) when allocating stacks

2024-03-23 Thread Sergey Bugaev
Previously, HTL would always allocate non-executable stacks.  This has
never been noticed, since GNU Mach on x86 ignores VM_PROT_EXECUTE and
makes all pages implicitly executable.  Since GNU Mach on AArch64
supports non-executable pages, HTL forgetting to pass VM_PROT_EXECUTE
immediately breaks any code that (unfortunately, still) relies on
executable stacks.

Signed-off-by: Sergey Bugaev 
---
 sysdeps/htl/Versions  | 4 
 sysdeps/mach/htl/pt-stack-alloc.c | 9 +++--
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/sysdeps/htl/Versions b/sysdeps/htl/Versions
index 3a3b1e8b..7b5450d2 100644
--- a/sysdeps/htl/Versions
+++ b/sysdeps/htl/Versions
@@ -12,4 +12,8 @@ libc {
 pthread_spin_destroy; pthread_spin_init; pthread_spin_lock;
 pthread_spin_trylock; pthread_spin_unlock;
   }
+
+  GLIBC_PRIVATE {
+__vm_map;
+  }
 }
diff --git a/sysdeps/mach/htl/pt-stack-alloc.c 
b/sysdeps/mach/htl/pt-stack-alloc.c
index 61974bd5..0597770b 100644
--- a/sysdeps/mach/htl/pt-stack-alloc.c
+++ b/sysdeps/mach/htl/pt-stack-alloc.c
@@ -31,9 +31,14 @@ int
 __pthread_stack_alloc (void **stackaddr, size_t stacksize)
 {
   error_t err;
+  vm_prot_t prot = VM_PROT_READ | VM_PROT_WRITE;
 
-  err = __vm_allocate (__mach_task_self (), (vm_offset_t *) stackaddr,
-  stacksize, TRUE);
+  if (GL(dl_stack_flags) & PF_X)
+prot |= VM_PROT_EXECUTE;
+
+  err = __vm_map (__mach_task_self (), (vm_offset_t *) stackaddr,
+ stacksize, 0, TRUE, MEMORY_OBJECT_NULL, 0, FALSE,
+ prot, VM_PROT_ALL, VM_INHERIT_COPY);
 
   if (err == KERN_NO_SPACE)
 err = EAGAIN;
-- 
2.44.0




[PATCH v2 00/20] aarch64-gnu port & GNU/Hurd on AArch64 progress

2024-03-23 Thread Sergey Bugaev
Hello!

This is v2 of my work on the aarch64-gnu port, aka GNU/Hurd on 64-bit
ARM. v1 is here [0].

[0]: https://sourceware.org/pipermail/libc-alpha/2024-January/153675.html

Last time, Joseph Myers has pointed out that the aarch64-gnu port can
not be merged into glibc until aarch64-gnu support is upstream in all of
glibc's build-time dependencies. That is still not the case, so this
patchset can not be merged yet; but otherwise it should be in a fairly
mergeable state. It does not yet anything to NEWS or
build-many-glibcs.py, though.

I'm porting this, again, to gather some feedback (hopefully more than
last time...), and at Maxim's request, so Linaro can test this on their
CI and ensure this doesn't break existing ports.

The upstreaming status of various aarch64-gnu components is,
specifically:

* Binutils patch to add the aarch64-gnu target is upstream and in the
  2.42 release;
* GCC patches to add aarch64-gnu target (& libgcc host) have been
  reviewed by ARM and Hurd port maintainers and should land upstream
  very soon;
* initial Hurd patches are upstream;
* glibc patches (this patchset) are not yet upstream;
* GNU Mach changes are not upstream, and upstreaming story is unclear;
* GNU MIG needs no changes, it just works.

Last time, there was no AArch64 port of GNU Mach, and so the only
testing I have done was running a simple statically-linked executable on
Linux under GDB -- which, nevertheless, helped me identify and fix a
number of issues.

Since then, however, I have been (some may say, relentlessly) working on
filling in the missing piece, namely porting gnumach (with important
help & contributions by Luca D.). I am happy to report that we now have
an experimental port of gnumach that builds and works on AArch64! While
that may sound impressive, note that various things about it are in an
extremely basic, proof-of-concept state rather than being seriously
production-ready; and also that Mach is a small kernel (indeed, a
microkernel), and it was designed from the start (back in the 80s) to be
portable, so most of the "buisness logic" functionality (virtual memory,
IPC, tasks/threads/scheduler) is explicitly arch-independent.

Despite the scary "WIP proof-of-concept" status, there is enough
functionality in Mach to run userland code, handle exceptions and
syscalls, interact with the MMU to implement all the expected virtual
memory semantics, schedule/switch tasks and threads, and so on.
Moreover, all of gnumach's userspace self-tests pass!

This meant there was enough things in place for me to try running glibc
on it, and the amazing thing is my simple test executable, the same one
I previously tested on Linux w/ GDB, just worked on real Mach without me
having to make any additional changes to the glibc side, or even
recompile it.

But I did not stop there, and got several of the core Hurd servers
working! Namely, these are ext2fs, exec, startup, auth, and proc
servers. All of them but ext2fs are dynamically linked; ld-aarch64.so.1
sucessfully locates and maps the programs themselves and their required
dependencies, and Mach pages in code and data pages from ext2fs as they
are accessed, transparently to the program, just as one would expect it
to.

It turned out that Mach on i386 and x86_64 did not enforce the (lack of)
execute permission on pages, i.e. even pages mapped without
VM_PROT_EXECUTE were executable in practice. This caused a number of
bugs related to mapping executable stacks to go unnoticed, there were
issues in all of Mach, glibc, and the Hurd's exec server related to
not creating executable stacks as actually executable. As I implemented
the execute permission properly in Mach on AArch64 (indeed, I even
support execute-only pages when the hardware implements FEAT_EPAN), I
have encountered all of those oversights one by one when trying to run
progressively more code, and have hopefully fixed them all. Hopefully
we'll stop requiring executable stacks for glibc and Hurd libraries some
time, and then we'll get working non-executable stacks on AArch64.

As expected, I have done some tweaks to the AArch64-specific Mach APIs
(primarily thread state and exception code definitions) compared to the
"preliminary sketches" of them that I posted in January, but they were
actually rather small. I've got some more confidence in the APIs now
after having implemented support for them from both sides now, and
having tested that it works in practice. No more backwards-incompatible
changes to AArch64-specific Mach APIs are expected (by me anyway); we'll
definetely want to add more things later (aarch64_debug_state for GDB,
PAC RPCs, and more), but those should be purely additive.

I have added a new Mach syscall (trap), thread_set_self_state (), to
implement sigreturn () on top of. I have originally hoped that it would
be possible to use the regular thread_set_state (mach_thread_self ())
call for it (special-casing it on AArch64 to allow setting the calling
thread's state), and indeed have 

[PATCH v2 05/20] hurd: Use the RETURN_ADDRESS macro

2024-03-23 Thread Sergey Bugaev
This gives us PAC stripping on AArch64.

Signed-off-by: Sergey Bugaev 
---

PAC is still not implemented on gnumach side, though.

 sysdeps/mach/hurd/init-first.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sysdeps/mach/hurd/init-first.c b/sysdeps/mach/hurd/init-first.c
index 22c35747..5777c44c 100644
--- a/sysdeps/mach/hurd/init-first.c
+++ b/sysdeps/mach/hurd/init-first.c
@@ -222,7 +222,7 @@ _hurd_stack_setup (void **argptr)
  this may not be a valid pointer in case we're supposed to receive the
  arguments from the exec server, so we can not dereference it yet.  */
 
-  void *caller = __builtin_extract_return_addr (__builtin_return_address (0));
+  void *caller = RETURN_ADDRESS (0);
   /* Init the essential things.  */
   first_init ();
 
-- 
2.44.0




[PATCH v2 03/20] Allow glibc to be compiled without EXEC_PAGESIZE

2024-03-23 Thread Sergey Bugaev
We would like to avoid statically defining any specific page size on
aarch64-gnu, and instead make sure that everything uses the dynamic
page size, available via vm_page_size and GLRO(dl_pagesize).

There are currently a few places in glibc that require EXEC_PAGESIZE
to be defined. Per Roland's suggestion [0], drop the static
GLRO(dl_pagesize) initializers (for now, only if EXEC_PAGESIZE is not
defined), and don't require EXEC_PAGESIZE definition for libio to
enable mmap usage.

[0]: https://mail.gnu.org/archive/html/bug-hurd/2011-10/msg00035.html

Signed-off-by: Sergey Bugaev 
---

Same patch as last time. At least in the Hurd port, GLRO(dl_pagesize)
is one of the very things to get initialized, so this shouldn't cause
any initialization order issues. But, if it's really undesirable for
EXEC_PAGESIZE to be dropped, we could of course also define
EXEC_PAGESIZE to some large value (16K?) on aarch64-gnu, provided that
nothing actually tries to use it for anything.

PAGE_SIZE is 4k in the current AArch64 GNU Mach, for what it's worth,
but this is intended to eventually be build-time configurable.

 elf/dl-support.c | 6 +-
 elf/rtld.c   | 2 ++
 libio/libioP.h   | 2 +-
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/elf/dl-support.c b/elf/dl-support.c
index 451932dd..cb0bbd21 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -135,7 +135,11 @@ void *_dl_random;
 #include 
 #include 
 
-size_t _dl_pagesize = EXEC_PAGESIZE;
+size_t _dl_pagesize
+#ifdef EXEC_PAGESIZE
+  = EXEC_PAGESIZE
+#endif
+;
 
 size_t _dl_minsigstacksize = CONSTANT_MINSIGSTKSZ;
 
diff --git a/elf/rtld.c b/elf/rtld.c
index ac4bb236..18d73f19 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -358,7 +358,9 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
 ._dl_debug_fd = STDERR_FILENO,
 ._dl_lazy = 1,
 ._dl_fpu_control = _FPU_DEFAULT,
+#ifdef EXEC_PAGESIZE
 ._dl_pagesize = EXEC_PAGESIZE,
+#endif
 ._dl_inhibit_cache = 0,
 ._dl_profile_output = "/var/tmp",
 
diff --git a/libio/libioP.h b/libio/libioP.h
index 1af287b1..1a7f547e 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -852,7 +852,7 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
 #  define MAP_ANONYMOUS MAP_ANON
 # endif
 
-# if !defined(MAP_ANONYMOUS) || !defined(EXEC_PAGESIZE)
+# if !defined(MAP_ANONYMOUS)
 #  undef _G_HAVE_MMAP
 #  define _G_HAVE_MMAP 0
 # endif
-- 
2.44.0




Re: [PATCH gcc 1/3] Move GNU/Hurd startfile spec from config/i386/gnu.h to config/gnu.h

2024-03-23 Thread Sergey Bugaev
On Wed, Mar 20, 2024 at 10:20 PM Thomas Schwinge  wrote:
> Hi!

Hi Thomas,

> Sergey, great work on aarch64 GNU/Hurd!  (... where these GCC bits
> clearly were the less complicated part...)  ;-)

thanks! (and indeed they were :)

> Please re-submit with ChangeLog updates added to the Git commit logs; see
>  ->
> , and/or 'git log'
> for guidance.  You may use
> 'contrib/gcc-changelog/git_check_commit.py --print-changelog' to verify.

Done so, and git_check_commit.py seems happy with my attempt. I
rebased (fixing a trivial merge conflict) and posted v2, please take a
look.

Sergey



[PATCH v2 1/3] Move GNU/Hurd startfile spec from config/i386/gnu.h to config/gnu.h

2024-03-23 Thread Sergey Bugaev
Since it's not i386-specific; this makes it possible to reuse it for other
architectures.

Also, add a warning for the case gnu.h is specified before gnu-user.h, which
would cause gnu-user's version of the spec to override gnu's, and not the other
way around as it's intended. The i?86-gnu target currently specifies them in
the right order, but it's easy to accidentally put them in a wrong order.

gcc/Changelog:

* config/i386/gnu.h: Move GNU/Hurd STARTFILE_SPEC from here...
* config/gnu.h: ...to here.

Signed-off-by: Sergey Bugaev 
---
 gcc/config/gnu.h  | 16 
 gcc/config/i386/gnu.h | 11 ---
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/gcc/config/gnu.h b/gcc/config/gnu.h
index ac99f7605..e2a33baf0 100644
--- a/gcc/config/gnu.h
+++ b/gcc/config/gnu.h
@@ -31,3 +31,19 @@ along with GCC.  If not, see <http://www.gnu.org/licenses/>.
builtin_assert ("system=unix"); \
builtin_assert ("system=posix");\
 } while (0)
+
+
+#ifndef GNU_USER_TARGET_STARTFILE_SPEC
+# warning This file should be included after gnu-user.h, to override its 
STARTFILE_SPEC
+#endif
+
+#undef STARTFILE_SPEC
+#if defined HAVE_LD_PIE
+#define STARTFILE_SPEC \
+  "%{!shared: 
%{pg|p|profile:%{static-pie:grcrt0.o%s;static:gcrt0.o%s;:gcrt1.o%s};static-pie:rcrt0.o%s;static:crt0.o%s;"
 PIE_SPEC ":Scrt1.o%s;:crt1.o%s}} \
+   crti.o%s %{static:crtbeginT.o%s;shared|static-pie|" PIE_SPEC 
":crtbeginS.o%s;:crtbegin.o%s}"
+#else
+#define STARTFILE_SPEC \
+  "%{!shared: 
%{pg|p|profile:%{static:gcrt0.o%s;:gcrt1.o%s};static:crt0.o%s;:crt1.o%s}} \
+   crti.o%s %{static:crtbeginT.o%s;shared:crtbeginS.o%s;:crtbegin.o%s}"
+#endif
diff --git a/gcc/config/i386/gnu.h b/gcc/config/i386/gnu.h
index 3f42714d1..af1d55887 100644
--- a/gcc/config/i386/gnu.h
+++ b/gcc/config/i386/gnu.h
@@ -24,17 +24,6 @@ along with GCC.  If not, see <http://www.gnu.org/licenses/>.
 #undef GNU_USER_DYNAMIC_LINKER
 #define GNU_USER_DYNAMIC_LINKER "/lib/ld.so"
 
-#undef STARTFILE_SPEC
-#if defined HAVE_LD_PIE
-#define STARTFILE_SPEC \
-  "%{!shared: 
%{pg|p|profile:%{static-pie:grcrt0.o%s;static:gcrt0.o%s;:gcrt1.o%s};static-pie:rcrt0.o%s;static:crt0.o%s;"
 PIE_SPEC ":Scrt1.o%s;:crt1.o%s}} \
-   crti.o%s %{static:crtbeginT.o%s;shared|static-pie|" PIE_SPEC 
":crtbeginS.o%s;:crtbegin.o%s}"
-#else
-#define STARTFILE_SPEC \
-  "%{!shared: 
%{pg|p|profile:%{static:gcrt0.o%s;:gcrt1.o%s};static:crt0.o%s;:crt1.o%s}} \
-   crti.o%s %{static:crtbeginT.o%s;shared:crtbeginS.o%s;:crtbegin.o%s}"
-#endif
-
 #ifdef TARGET_LIBC_PROVIDES_SSP
 
 /* i386 glibc provides __stack_chk_guard in %gs:0x14.  */
-- 
2.44.0




[PATCH v2 3/3] libgcc: Add basic support for aarch64-gnu (GNU/Hurd on AArch64)

2024-03-23 Thread Sergey Bugaev
There is currently no unwinding implementation.

libgcc/ChangeLog:

* config.host: Recognize aarch64*-*-gnu* hosts.
* config/aarch64/gnu-unwind.h: New file.
* config/aarch64/heap-trampoline.c
(allocate_trampoline_page): Support GNU/Hurd.

Signed-off-by: Sergey Bugaev 
---
 libgcc/config.host  |  9 +++
 libgcc/config/aarch64/gnu-unwind.h  | 36 +
 libgcc/config/aarch64/heap-trampoline.c |  4 +--
 3 files changed, 47 insertions(+), 2 deletions(-)
 create mode 100644 libgcc/config/aarch64/gnu-unwind.h

diff --git a/libgcc/config.host b/libgcc/config.host
index 59a42d3a0..e75a7af64 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -448,6 +448,15 @@ aarch64*-*-linux*)
tmake_file="${tmake_file} t-dfprules"
tmake_file="${tmake_file} ${cpu_type}/t-heap-trampoline"
;;
+aarch64*-*-gnu*)
+   extra_parts="$extra_parts crtfastmath.o"
+   md_unwind_header=aarch64/gnu-unwind.h
+   tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
+   tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc"
+   tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
+   tmake_file="${tmake_file} t-dfprules"
+   tmake_file="${tmake_file} ${cpu_type}/t-heap-trampoline"
+   ;;
 aarch64*-*-vxworks7*)
extra_parts="$extra_parts crtfastmath.o"
md_unwind_header=aarch64/aarch64-unwind.h
diff --git a/libgcc/config/aarch64/gnu-unwind.h 
b/libgcc/config/aarch64/gnu-unwind.h
new file mode 100644
index 0..d9e485a18
--- /dev/null
+++ b/libgcc/config/aarch64/gnu-unwind.h
@@ -0,0 +1,36 @@
+/* DWARF2 EH unwinding support for GNU Hurd: aarch64.
+   Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* Always include AArch64 unwinder header file.  */
+#include "config/aarch64/aarch64-unwind.h"
+
+#ifndef inhibit_libc
+
+#include 
+
+/*
+ * TODO: support for aarch64 needs to be implemented.
+ */
+
+#endif /* ifndef inhibit_libc */
diff --git a/libgcc/config/aarch64/heap-trampoline.c 
b/libgcc/config/aarch64/heap-trampoline.c
index 885df629d..26957a3ee 100644
--- a/libgcc/config/aarch64/heap-trampoline.c
+++ b/libgcc/config/aarch64/heap-trampoline.c
@@ -29,7 +29,7 @@ void *allocate_trampoline_page (void);
 void __gcc_nested_func_ptr_created (void *chain, void *func, void *dst);
 void __gcc_nested_func_ptr_deleted (void);
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__gnu_hurd__)
 static const unsigned char aarch64_trampoline_insns[6][4] = {
   {0x5f, 0x24, 0x03, 0xd5}, /* hint34 */
   {0xb1, 0x00, 0x00, 0x58}, /* ldr x17, .+20 */
@@ -82,7 +82,7 @@ allocate_trampoline_page (void)
 {
   void *page;
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__gnu_hurd__)
   page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
   MAP_ANON | MAP_PRIVATE, 0, 0);
 #elif __APPLE__
-- 
2.44.0




[PATCH v2 2/3] aarch64: Add support for aarch64-gnu (GNU/Hurd on AArch64)

2024-03-23 Thread Sergey Bugaev
Coupled with a corresponding binutils patch, this produces a toolchain that can
sucessfully build working binaries targeting aarch64-gnu.

gcc/Changelog:

* config.gcc: Recognize aarch64*-*-gnu* targets.
* config/aarch64/aarch64-gnu.h: New file.

Signed-off-by: Sergey Bugaev 
---
 gcc/config.gcc   |  6 +++
 gcc/config/aarch64/aarch64-gnu.h | 68 
 2 files changed, 74 insertions(+)
 create mode 100644 gcc/config/aarch64/aarch64-gnu.h

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 87a5c92b6..9d935164c 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -1264,6 +1264,12 @@ aarch64*-*-linux*)
done
TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'`
;;
+aarch64*-*-gnu*)
+tm_file="${tm_file} elfos.h gnu-user.h gnu.h glibc-stdint.h"
+tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h 
aarch64/aarch64-gnu.h"
+tmake_file="${tmake_file} aarch64/t-aarch64"
+tm_defines="${tm_defines}  TARGET_DEFAULT_ASYNC_UNWIND_TABLES=1"
+   ;;
 aarch64*-wrs-vxworks*)
 tm_file="${tm_file} elfos.h aarch64/aarch64-elf.h"
 tm_file="${tm_file} vx-common.h vxworks.h aarch64/aarch64-vxworks.h"
diff --git a/gcc/config/aarch64/aarch64-gnu.h b/gcc/config/aarch64/aarch64-gnu.h
new file mode 100644
index 0..ee5494034
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-gnu.h
@@ -0,0 +1,68 @@
+/* Definitions for AArch64 running GNU/Hurd.
+   Copyright (C) 2009-2024 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_AARCH64_GNU_H
+#define GCC_AARCH64_GNU_H
+
+#define GNU_USER_DYNAMIC_LINKER 
"/lib/ld-aarch64%{mbig-endian:_be}%{mabi=ilp32:_ilp32}.so.1"
+
+#define CPP_SPEC "%{pthread:-D_REENTRANT}"
+
+#define GNU_TARGET_LINK_SPEC  "%{h*}   \
+   %{static:-Bstatic}  \
+   %{shared:-shared}   \
+   %{symbolic:-Bsymbolic}  \
+   %{!static:%{!static-pie:\
+ %{rdynamic:-export-dynamic}   \
+ %{!shared:-dynamic-linker " GNU_USER_DYNAMIC_LINKER "}}} \
+   %{static-pie:-Bstatic -pie --no-dynamic-linker -z text} \
+   -X  \
+   %{mbig-endian:-EB} %{mlittle-endian:-EL} \
+   -maarch64gnu%{mabi=ilp32:32}%{mbig-endian:b}"
+
+
+#define LINK_SPEC GNU_TARGET_LINK_SPEC AARCH64_ERRATA_LINK_SPEC
+
+#define GNU_USER_TARGET_MATHFILE_SPEC \
+  "%{Ofast|ffast-math|funsafe-math-optimizations:%{!shared:crtfastmath.o%s}}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC   \
+  GNU_USER_TARGET_MATHFILE_SPEC " " \
+  GNU_USER_TARGET_ENDFILE_SPEC
+
+#define TARGET_OS_CPP_BUILTINS()   \
+  do   \
+{  \
+   GNU_USER_TARGET_OS_CPP_BUILTINS();  \
+}  \
+  while (0)
+
+#define TARGET_ASM_FILE_END aarch64_file_end_indicate_exec_stack
+
+/* Uninitialized common symbols in non-PIE executables, even with
+   strong definitions in dependent shared libraries, will resolve
+   to COPY relocated symbol in the executable.  See PR65780.  */
+#undef TARGET_BINDS_LOCAL_P
+#define TARGET_BINDS_LOCAL_P default_binds_local_p_2
+
+/* Define this to be nonzero if static stack checking is supported.  */
+#define STACK_CHECK_STATIC_BUILTIN 1
+
+#endif  /* GCC_AARCH64_GNU_H */
-- 
2.44.0




Re: [PATCH 01/10] term: Fix function prototype

2024-03-23 Thread Sergey Bugaev
On Sat, Mar 23, 2024 at 3:06 PM Samuel Thibault  wrote:
> Applied the whole series, thanks!

Looks like "[PATCH 07/10] exec: Add support for AArch64 executables"
fell through the cracks...

Sergey



[PATCH 09/10] proc: Add support for AArch64 in uname

2024-03-23 Thread Sergey Bugaev
Since no CPU subtypes are defined for CPU_TYPE_ARM64, just report the
type, same as for x86_64.

Sample uname(2) output:

sysname: GNU
release: 0.9
version: GNU-Mach 1.8/Hurd-0.9
machine: aarch64
---
 proc/cpu-types.c | 3 +++
 proc/host.c  | 4 ++--
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/proc/cpu-types.c b/proc/cpu-types.c
index 3d89d5a7..41af0888 100644
--- a/proc/cpu-types.c
+++ b/proc/cpu-types.c
@@ -35,6 +35,9 @@ const char *const mach_cpu_types[] =
 #endif
 #ifdef CPU_TYPE_X86_64
 [CPU_TYPE_X86_64] = "x86_64",
+#endif
+#ifdef CPU_TYPE_ARM64
+[CPU_TYPE_ARM64] = "aarch64",
 #endif
   };
 
diff --git a/proc/host.c b/proc/host.c
index 0197fecf..e0aff20a 100644
--- a/proc/host.c
+++ b/proc/host.c
@@ -355,11 +355,11 @@ initialize_version_info (void)
   assert_backtrace (! err);
   snprintf (uname_info.machine, sizeof uname_info.machine,
"%s"
-#ifndef __x86_64__
+#if !defined (__x86_64__) && !defined (__aarch64__)
"-%s"
 #endif
, mach_cpu_types[info.cpu_type]
-#ifndef __x86_64__
+#if !defined (__x86_64__) && !defined (__aarch64__)
, mach_cpu_subtypes[info.cpu_type][info.cpu_subtype]
 #endif
);
-- 
2.44.0




[PATCH 01/10] term: Fix function prototype

2024-03-23 Thread Sergey Bugaev
struct bottomhalf.mdmstate is of type error_t (*)(int *state).

Fixes -Wincompatible-pointer-types, which is a hard error by default
in GCC 14.
---
 term/hurdio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/term/hurdio.c b/term/hurdio.c
index c6e14a4a..eab59b72 100644
--- a/term/hurdio.c
+++ b/term/hurdio.c
@@ -614,7 +614,7 @@ hurdio_mdmctl (int how, int bits)
 
 
 static int
-hurdio_mdmstate (void)
+hurdio_mdmstate (int *state)
 {
   int oldbits;
 
-- 
2.44.0




[PATCH 06/10] exec: Stop relying on address space size

2024-03-23 Thread Sergey Bugaev
The code here just wants to deallocate the whole address space, and Mach
already contains the logic to limit the passed-in range to the vm_map's
actual bounds (see VM_MAP_RANGE_CHECK).
---
 exec/exec.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/exec/exec.c b/exec/exec.c
index f6788520..ac226f9a 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -1219,9 +1219,7 @@ do_exec (file_t file,
   munmap ((caddr_t) threads, nthreads * sizeof (thread_t));
 
   /* Deallocate the entire virtual address space of the task.  */
-
-  vm_deallocate (oldtask,
-VM_MIN_ADDRESS, VM_MAX_ADDRESS - VM_MIN_ADDRESS);
+  vm_deallocate (oldtask, 0, (vm_size_t) -1);
 
   /* Nothing is supposed to go wrong any more.  If anything does, the
 old task is now in a hopeless state and must be killed.  */
-- 
2.44.0




[PATCH 08/10] elfcore: Add support for saving AArch64 registers

2024-03-23 Thread Sergey Bugaev
---
 exec/elfcore.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/exec/elfcore.c b/exec/elfcore.c
index c6aa2bc8..8c85b13b 100644
--- a/exec/elfcore.c
+++ b/exec/elfcore.c
@@ -187,6 +187,32 @@ fetch_thread_fpregset (thread_t thread, prfpregset_t 
*fpregs)
   (thread_state_t) fpregs, );
 }
 
+#elif defined (AARCH64_THREAD_STATE)
+
+# define ELF_MACHINE   EM_AARCH64
+
+static inline void
+fetch_thread_regset (thread_t thread, prgregset_t *gregs)
+{
+  mach_msg_type_number_t count = AARCH64_THREAD_STATE_COUNT;
+  _Static_assert (sizeof (prgregset_t) == sizeof (struct aarch64_thread_state),
+ "thread state mismatch");
+  (void) thread_get_state (thread, AARCH64_THREAD_STATE,
+  (thread_state_t) gregs, );
+  assert_backtrace (count == AARCH64_THREAD_STATE_COUNT);
+}
+
+static inline void
+fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs)
+{
+  mach_msg_type_number_t count = AARCH64_FLOAT_STATE_COUNT;
+  _Static_assert (sizeof (prfpregset_t) == sizeof (struct aarch64_float_state),
+ "float state mismatch");
+  (void) thread_get_state (thread, AARCH64_FLOAT_STATE,
+  (thread_state_t) fpregs, );
+  assert_backtrace (count == AARCH64_FLOAT_STATE_COUNT);
+}
+
 #else
 # warning "do not understand this machine flavor, no registers in dumps"
 # define ELF_MACHINE   EM_NONE
-- 
2.44.0




[PATCH 07/10] exec: Add support for AArch64 executables

2024-03-23 Thread Sergey Bugaev
This maps to EM_AARCH64.  Just like the x86_64 branch, we only compile
this code if CPU_TYPE_ARM64 is defined in Mach headers, to avoid
raising Mach version requirement on other architectures; and we
explicitly enable the branch when building for AArch64 itself, to get
a build error if CPU_TYPE_ARM64 is somehow not defined.
---
 exec/hostarch.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/exec/hostarch.c b/exec/hostarch.c
index ed50e0a8..81bbeb63 100644
--- a/exec/hostarch.c
+++ b/exec/hostarch.c
@@ -90,6 +90,11 @@ elf_machine_matches_host (ElfW(Half) e_machine)
 case CPU_TYPE_HPPA:
   CACHE (e_machine == EM_PARISC);
 
+#if defined (CPU_TYPE_ARM64) || defined(__aarch64__)
+case CPU_TYPE_ARM64:
+  CACHE (e_machine == EM_AARCH64);
+#endif
+
 default:
   return EGRATUITOUS;  /* XXX */
 }
-- 
2.44.0




[PATCH 10/10] boot: Add support for AArch64

2024-03-23 Thread Sergey Bugaev
---
 boot/userland-boot.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/boot/userland-boot.c b/boot/userland-boot.c
index f407f0a6..496628eb 100644
--- a/boot/userland-boot.c
+++ b/boot/userland-boot.c
@@ -334,6 +334,17 @@ boot_script_exec_cmd (void *hook,
 thread_set_state (thread, ALPHA_THREAD_STATE,
  (thread_state_t) , reg_size);
   }
+#elif defined (AARCH64_THREAD_STATE_COUNT)
+  {
+struct aarch64_thread_state regs;
+reg_size = AARCH64_THREAD_STATE_COUNT;
+thread_get_state (thread, AARCH64_THREAD_STATE,
+ (thread_state_t) , _size);
+regs.sp = (long) arg_pos;
+regs.pc = (long) startpc;
+thread_set_state (thread, AARCH64_THREAD_STATE,
+ (thread_state_t) , reg_size);
+  }
 #else
 # error needs to be ported
 #endif
-- 
2.44.0




[PATCH 02/10] exec: Fix creating executable stacks

2024-03-23 Thread Sergey Bugaev
The previous logic had two independent issues:

* We need to make the stack executable if either the program or its ELF
  interpreter requires executable stack.  In practice, it's common for
  the program itself to not require executable stack, but ld.so (glibc)
  needs it.

* mach_setup_thread () allocates stacks with a simple vm_allocate (),
  which creates non-executable memory.  So if an executable stack is
  required, the stack has to be vm_protect'ed to enable execution, not
  the other way around.  As the comment suggest, it would've been better
  to use vm_map () with the desired protection directly.
---
 exec/exec.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/exec/exec.c b/exec/exec.c
index 639564cb..f6788520 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -1335,11 +1335,12 @@ do_exec (file_t file,
   if (e.error)
 goto out;
 
-  /* It would probably be better to change mach_setup_thread so
- it does a vm_map with the right permissions to start with.  */
-  if (!e.info.elf.execstack)
+  /* mach_setup_thread () creates non-executable stacks (with vm_allocate ()).
+ It would probably be better to change mach_setup_thread () so it does
+ a vm_map () with the right permissions to start with.  */
+  if (e.info.elf.execstack || (e.interp.section && interp.info.elf.execstack))
 e.error = vm_protect (newtask, boot->stack_base, boot->stack_size,
- 0, VM_PROT_READ | VM_PROT_WRITE);
+ 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
 
   if (oldtask != newtask && oldtask != MACH_PORT_NULL)
 {
-- 
2.44.0




[PATCH 05/10] libshouldbeinlibc: Stop relying on address space size

2024-03-23 Thread Sergey Bugaev
While GNU Mach on AArch64 still exports VM_MIN_ADDRESS / VM_MAX_ADDRESS
for compatibility, we should try to rely on it less when possible; in
the future we might be able to stop exporting them from Mach.  The code
here really just wants to wire everything in its address space, and the
wire_segment_internal () routine already queries for actually present
memory regions dynamically.
---
 libshouldbeinlibc/wire.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libshouldbeinlibc/wire.c b/libshouldbeinlibc/wire.c
index ea6c5526..d1c745a8 100644
--- a/libshouldbeinlibc/wire.c
+++ b/libshouldbeinlibc/wire.c
@@ -136,7 +136,7 @@ wire_task_self (void)
   if (err)
 return err;
 
-  err = wire_segment_internal (VM_MIN_ADDRESS, VM_MAX_ADDRESS, host);
+  err = wire_segment_internal (0, (vm_size_t) -1, host);
   if (err)
 goto out;
 
-- 
2.44.0




[PATCH 03/10] Make long & friends 64-bit on 64-bit platforms

2024-03-23 Thread Sergey Bugaev
Not only on x86_64.
---
 hurd/hurd_types.defs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hurd/hurd_types.defs b/hurd/hurd_types.defs
index 9f176fef..0086d139 100644
--- a/hurd/hurd_types.defs
+++ b/hurd/hurd_types.defs
@@ -425,7 +425,7 @@ type flock_t = struct {
 };
 
 type unsigned_int = uint32_t;
-#if defined(__x86_64__)
+#if defined(__LP64__)
 type long = int64_t;
 type unsigned_long = uint64_t;
 
-- 
2.44.0




[PATCH 04/10] proc: Only try host_kernel_version () on i386

2024-03-23 Thread Sergey Bugaev
None of the new architectures are going to have it; that isn't specific
to x86_64.
---
 proc/host.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/proc/host.c b/proc/host.c
index 823bda53..0197fecf 100644
--- a/proc/host.c
+++ b/proc/host.c
@@ -371,8 +371,8 @@ initialize_version_info (void)
   server_versions_nalloc = 10;
 
   err = host_get_kernel_version (mach_host_self (), kv);
-#ifndef __x86_64__
-  /* We don't support host_kernel_version for x86_64. */
+#ifdef __i386__
+  /* We only supported host_kernel_version on i386.  */
   if (err == MIG_BAD_ID)
 {
   /* Delete after some time. */
-- 
2.44.0




Re: [PATCH] console-client: deallocate the port once finished with it

2024-03-13 Thread Sergey Bugaev
On Wed, Mar 13, 2024 at 1:56 PM Etienne Brateau
 wrote:
>  console-client/trans.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/console-client/trans.c b/console-client/trans.c
> index b7d56cb0..a3d6dd3c 100644
> --- a/console-client/trans.c
> +++ b/console-client/trans.c
> @@ -898,6 +898,7 @@ console_setup_node (char *path)
>err = file_set_translator (node, 0, FS_TRANS_EXCL | FS_TRANS_SET, 0, 0, 0,
>  right, MACH_MSG_TYPE_COPY_SEND);
>mach_port_deallocate (mach_task_self (), right);
> +  ports_port_deref (newpi);

Makes sense to me.

While at it, you could also replace ports_get_send_right () +
MACH_MSG_TYPE_COPY_SEND + mach_port_deallocate () with ports_get_right
() + MACH_MSG_TYPE_MAKE_SEND.

Sergey



Re: [RFC PATCH 00/23] aarch64-gnu port

2024-03-11 Thread Sergey Bugaev
On Mon, Mar 11, 2024 at 4:48 PM H.J. Lu  wrote:
> I think hurd maintainers can approve and check in all hurd specific
> changes now even if they won't build.   The generic changes should
> be looked at more closely so that they have no impacts on any
> future Linux changes and future Linux changes won't be blocked
> because of hurd.

On Mon, Mar 11, 2024 at 5:15 PM Maxim Kuvyrkov
 wrote:
> Hi Sergey,
>
> Would you please update and re-post your patch series, so that reviewers can 
> check that it doesn't break existing targets?

Hi Maxim, H.J.,

"Even if they won't build" won't stay that way for long: since the
time I posted this glibc patchset, I've been working on porting GNU
Mach to AArch64, and while that work is not yet upstream, my branch of
gnumach compiles, boots in QEMU, and passes the testsuite! (And I am
*so* excited about this!) Moreover, the simple glibc-based program
that I've used for testing in GDB (as mentioned in the cover letter)
starts up and reaches main() too! I have not rebuilt it since then,
meaning that ABI indeed matches between the kernel and this glibc
patchset.

So yes, it might be the time for me to rebase & update this patchset,
and post it again. I'll start working on that then.

By the way, while I have a somewhat better understanding of AArch64 &
ARM-based systems now, I'd still appreciate any reviews / insights /
pointers.

Sergey



Re: [PATCH 1/3 gnumach] vm_map: Fix deadlock in vm code

2024-02-21 Thread Sergey Bugaev
On Wed, Feb 21, 2024 at 9:44 PM Samuel Thibault  wrote:
> Damien Zammit, le mer. 21 févr. 2024 13:45:59 +, a ecrit:
> > Authored-by: Sergey Bugaev 

> IIRC you got to see which kind of deadlock we are protecting from here?
> I'd be very useful to document it here, so next people reading this get
> to know.

I didn't document the exact deadlock in the code, since the deadlock
is only a manifestation of the actual issue, the actual issue being
that the entry was being modified by other threads while accessed
inside vm_fault_wire(). This is -- for one thing, technically
undefined behavior -- but also will _of course_ break any kind of
logic that works with the entry's offset / address range. It could be
worse than a deadlock. So what I wanted to emphasize in the code is
that we should make sure the entry is not concurrently read and
modified, and I was going to describe the actual deadlock we've
witnessed in the commit message.

So let's go with that; I'll re-send this patch myself with a detailed
commit message and reworked comment.

> >[...] We trust that the
> >* kernel threads are well-behaved, and therefore will
> >* not do anything destructive to this region of the map
> >* while we have it unlocked.
>
> Are we not here precisely in the case that they are not well-behaved?

No. The threads are well-behaved, but turns out that's not quite
enough, because, as the new comment says, in the face of clipping and
coalescing entries, even well-behaved, well-intentioned operations on
*adjacent* VM regions can affect the same entry -- in fact, the entry
can get freed altogether if it gets coalesced into the previous entry,
why would create a use-after-free.

> The comment probably deserves an update, to make the situation cler.

I thought it was clear enough, but evidently it wasn't. I'll amend it.

> > +  * Once we unlock the map, even well-intentioned operations
> > +  * on adjacent VM regions can end up affecting our entry,
> > +  * due to clipping and coalescing entries.  So, make a
> > +  * temporary copy of the entry, and pass that to vm_fault_wire()
> > +  * instead of the original.
>
> We need to be very careful with such a thing. If it's a copy that is
> given to further function calls, we need to make sure that they won't
> try to modify it, i.e. add const qualifiers on the entry parameter all
> along to vm_fault_wire and its callees being passed entry.

That's a good idea, yes.

>
> That being said, this doesn't seem completely safe to me: in the end
> vm_fault_wire_fast uses the object field, are we sure that the object
> won't disappear? Or are we sure it won't because "kernel threads are
> well-behaved"? (but I don't really know how we are sure of this, so this
> probably also deserves documenting).

We are sure because kernel threads (or rather, any threads running in
the kernel) are well-behaved, yes. We trust that they won't unmap the
mapping while it's being wired, and the mapping (the entry) keeps the
object alive.

But... now that I think of it, we do also coalesce objects. So we
better keep a second reference on the object over vm_fault_wire
indeed.

> > +  *
> >* HACK HACK HACK HACK
> >*/
> >   if (vm_map_pmap(map) == kernel_pmap) {
> > + /*
> > +  *  TODO: Support wiring more than one entry
> > +  *  in the kernel map at a time.
> > +  */
> > + assert(start->vme_next == end);
>
> Are we sure that this currently is never to happen?

Not really. I don't expect the kernel to do this anywhere, but I don't
know for sure. Please try running some complex workloads with this
patch, and see if you catch this being not so?

There isn't anything fundamentally incompatible with supporting
multi-entry wiring here, I just didn't want to do an alloca.

> > + entry_copy = *start;
> >   vm_map_unlock(map); /* trust me ... */
> > - } else {
> > - vm_map_lock_set_recursive(map);
> > - vm_map_lock_write_to_read(map);
> > + vm_fault_wire(map, _copy);
>
> This is also assuming that for non-kernel_pmap there is just one entry
> for which to call vm_fault_wire, while userland can very well ask for
> wiring a wide range of memory, spanning various objects and whatnot.

No, this is still the kernel map branch (note that the "else" is being
deleted by the patch).

> AIUI you'd rather want the converse: inline the code for the kernel_pmap
> case, which is much more trivial since start->vme_next == end and thus
> no for loop to perform, just call vm_fault_wire and the locking stuff
> around, and be done.

That's exactly what this patch does, yes.

Sergey



Re: [PATCH gnumach] Add vm_pages_phys

2024-01-31 Thread Sergey Bugaev
On Wed, Jan 31, 2024 at 2:44 PM Samuel Thibault  wrote:
> > I see you used kmem_alloc_pageable() over kmem_alloc() that I
> > suggested. Why is that?
>
> Because I have seen it used so in other places,
> notably host_ipc_marequest_info, host_slab_info,
> host_virtual_physical_table_info

Yes, exactly because those functions don't hold VM locks :)

Look at mach_vm_object_pages_phys()/_mach_vm_object_pages() for an
example function that does (and actually does something close to what
you're implementing here?)

> > My understanding is the point of kmem_alloc()
> > is to be used in cases like this, when you don't want the routine
> > itself to fault while holding locks on VM objects/maps.
>
> That's quite subtle. Is that documented somewhere?

I don't think it is. There are a couple of /* can't fault while we
hold locks */ comments in ipc/mach_port.c, but there they do things
slightly differently: they allocate memory with vm_allocate(), and
then wire it with vm_map_pageable(). I don't know what the differences
between doing that vs kmem_alloc() are. There's also
kmem_alloc_wired() which does a very similar thing; the difference
appears to be that kmem_alloc_wired() uses kernel_object, while
kmem_alloc() creates a fresh anonymous VM object; apparently the
former prevents the allocated memory from being copied with
vm_map_copyin(), which means that memory basically cannot be sent in a
message. But I don't really understand how this works in detail.

Sergey



Re: [PATCH gnumach] Add vm_pages_phys

2024-01-31 Thread Sergey Bugaev
On Tue, Jan 30, 2024 at 9:45 PM Samuel Thibault  wrote:
> > > +kern_return_t vm_pages_phys(
> > > +   host_t  host,
> > > +   vm_map_tmap,
> > > +   vm_address_taddress,
> > > +   vm_size_t   size,
> >
> > This is supposed to be a number of pages rather than VM region size,
> > right?
>
> No, I followed the same principle as the vm_allocate etc. calls.
>
> In the function itself, count = atop(size).

Ack, indeed, I was looking at the wrong thing.

> > You're supposed to allocate your own buffer in this case, something like 
> > this:
>
> Ok, done so, thanks!

I see you used kmem_alloc_pageable() over kmem_alloc() that I
suggested. Why is that? My understanding is the point of kmem_alloc()
is to be used in cases like this, when you don't want the routine
itself to fault while holding locks on VM objects/maps.

Sergey



Re: [PATCH gnumach] Add vm_pages_phys

2024-01-29 Thread Sergey Bugaev
Hello,

On Mon, Jan 29, 2024 at 11:59 PM Samuel Thibault
 wrote:
> Please notably review the RPC part, I really don't know that much about
> mig.

Some nitpicks inline. Flávio, does what I'm saying below make sense to you?

> +/*
> + * vm_pages_phys returns information about a region of memory
> + */
> +kern_return_t vm_pages_phys(
> +   host_t  host,
> +   vm_map_tmap,
> +   vm_address_taddress,
> +   vm_size_t   size,

This is supposed to be a number of pages rather than VM region size,
right? Then it would be better off with a different name, and perhaps
type. Alternatively perhaps it _should_ be a VM region size?

> +   rpc_phys_addr_array_t   *pagespp,
> +   mach_msg_type_number_t  *countp)
> +{
> +   if (host == HOST_NULL)
> +   return KERN_INVALID_HOST;
> +   if (map == VM_MAP_NULL)
> +   return KERN_INVALID_TASK;
> +
> +   if (!page_aligned(address))
> +   return KERN_INVALID_ARGUMENT;
> +   if (!page_aligned(size))
> +   return KERN_INVALID_ARGUMENT;
> +
> +   mach_msg_type_number_t count = atop(size), cur;
> +
> +   if (*countp < count)
> +   return KERN_INVALID_ARGUMENT;

It's not an error if the passed-in buffer is smaller than what you're
planning to return. This is not even something that the user side of
the RPC controls, the buffer is fixed-size and allocated by MIG in the
reply message -- unless you use CountInOut, that is.

You're supposed to allocate your own buffer in this case, something like this:

rpc_phys_addr_array_t pages = *pagespp;
if (*countp < count) {
vm_offset_t allocated;
kr = kmem_alloc(ipc_kernel_map, , some_size);
if (kr != KERN_SUCCESS)
return kr;
pages = (rpc_phys_addr_array_t) allocated;
}

and at the end:

if (pages != *pagespp) {
vm_map_copy_t copy;
kr = vm_map_copyin(ipc_kernel_map, (vm_offset_t) pages,
some_size, TRUE, );
assert(kr == KERN_SUCCESS);
*pagespp = (rpc_phys_addr_array_t) copy;
}
*countp = count;

> +   *countp = count;
> +
> +   return KERN_SUCCESS;
> +}

OK. My current understanding is that you indeed do not need to
deallocate either the 'vm_map_t map' argument or the task port right
behind it on the success path here. But perhaps it would be clearer
with a comment stating that this is intentional (and not simply
forgotten).

Sergey



Re: [PATCH v2 2/4] Avoid conflicting types for 'copy_file_range'

2024-01-22 Thread Sergey Bugaev
On Mon, Jan 22, 2024 at 9:23 PM Sergey Bugaev  wrote:
> call such a function. For example on GNU/Linux, remove(2) is a stub,

(That was supposed to say revoke(2), of course.)



Re: [PATCH v2 2/4] Avoid conflicting types for 'copy_file_range'

2024-01-22 Thread Sergey Bugaev
Hello,

On Mon, Jan 22, 2024 at 8:05 PM Peter Maydell  wrote:
>
> On Thu, 18 Jan 2024 at 16:03, Manolo de Medici  
> wrote:
> >
> > Compilation fails on systems where copy_file_range is already defined as a
> > stub.
>
> What do you mean by "stub" here ? If the system headers define
> a prototype for the function, I would have expected the
> meson check to set HAVE_COPY_FILE_RANGE, and then this
> function doesn't get defined at all. That is, the prototype
> mismatch shouldn't matter because if the prototype exists we
> use the libc function, and if it doesn't then we use our version.

Let me answer :)

glibc has this stubs mechanism: a function can be declared in the
system headers, but only implemented as a stub that always fails with
ENOSYS (or some such). You get a linker warning at link time if you
call such a function. For example on GNU/Linux, remove(2) is a stub,
and if I try to use it, the code does compile, but I get

/usr/bin/ld: /tmp/ccLCnRnW.o: in function `main':
demo.c:(.text+0xa): warning: revoke is not implemented and will always fail

during linking. This is done by embedding a
'.gnu.warning.function-name' section inside libc.so (try readelf
--wide --section-headers /lib64/libc.so.6 | grep warning). You can
also find the list of stubs in the gnu/stubs.h header, which contains
definitions like __stub_revoke.

Meson's has_function() knows about this mechanism, and returns false
if the function is declared, but is actually just a stub (by looking
for "__stub_{func}" being defined); autoconf does, too. But as the
prototype is still declared (and the function technically exists, too,
even if it's a stub), you'll get errors if you define the same
function incompatibly yourself.

Sergey



Re: Announcing: a new Hurd distro, based on Alpine Linux

2024-01-21 Thread Sergey Bugaev
On Sun, Jan 21, 2024 at 10:14 PM  wrote:
> I'd be happy to buy a sourcehut account for it for a year.
>
> I'd also be happy to create a website for it and host it for a year.
> We should make this email (perhaps reword it) as the website's first
> blog post.
>
> Software with which we can build a static site (that runs on the hurd):
>
> ikiwiki
> Emacs org-mode (I vote this one)
> guile's Haunt  (I am having a hard time installing this on Debian
>  GNU/Hurd).

Yay :)

FWIW, I love how the Guile website looks, but that clearly has more to
do with the styling than with the choice of a backend framework.

As for {Git,packages} repos, I just learned that Gitea 1.20 has
built-in support for Alpine package registries [0][1], which is pretty
neat. If we could work out how to hook this up to a CI pipeline that
would build and publish packages (and that shouldn't be hard), this
would be perfect for us.

[0]: https://docs.gitea.com/next/usage/packages/packages/alpine (this
page says 1.20 is unreleased for some reason, but 1.20 has been
released back in July, and 1.21.4 is the current release)
[1]: https://github.com/go-gitea/gitea/pull/23714

So, what do you think, would you (or anyone else reading this) be able
to host a Gitea instance for this project? Hosting it on a Hurd system
would be cool, but not a requirement — we can do one thing at a time.

Any more naming ideas?

Sergey



Announcing: a new Hurd distro, based on Alpine Linux

2024-01-20 Thread Sergey Bugaev
Hello!

Those of you who made it to Joshua's belated New Year's party have
heard me mumble my way through announcing this: I have been working on
a new Hurd-based disto, based on the Alpine Linux distribution [0]!

[0] https://www.alpinelinux.org/about/

Now, before I go any further, I should say that this is not trying to
displace Debian or anything like that. We all love Debian GNU/Hurd,
and are thankful for Samuel's hard work that makes it possible. I am
using Debian, and will continue to do so. (Especially given that this
project might not succeed, after all.)

That being said, I have for a long time thought that the Hurd needed
more _distro diversity_. The other existing distro is Guix on the
Hurd, made by our Guix friends, which is great, and it seems to have
generated some interest towards the Hurd in the Guix community, and
some positive publicity for the Hurd too.

Historically, I know that there has been the Arch Hurd project [1]
(just look at all the excitement it has generated! [2]), but it seems
to have stalled. (By the way, if you're a fan of Arch who's interested
in the Hurd, I encourage you to revive Arch Hurd, that'd be so cool!)
There's been talks of Gentoo GNU/Hurd, but it doesn't look like
they've made much progress. (Fun story: I have once almost convinced a
friend of mine who was a Gentoo user to try and bootstrap a Hurd
version of Gentoo on his own.)

[1] https://archhurd.org/
[2] https://bbs.archlinux.org/viewtopic.php?pid=682472

Awesome as Debian is, there are issues with it. Firstly, the tooling
(and the social processes) used around Debian packaging seems rather
arcane and complicated for someone like myself who is not experienced
in Debian packaging. This is not a criticism; I'm sure it works great
for them! — but this also means that most of us in the already small
Hurd community are essentially unable to contribute to it.

Secondly, Debian GNU/Hurd being the full "grown-up" Debian distro has
— well, certainly a lot of upsides, and that's what makes it so
appealing — but also, I imagine, some downsides, in that it cannot
just be our little playground. For example, I imagine Debian cannot
ship the latest & greatest glibc master with all of my fixes, because
that might break Debian GNU/Linux, which has different expectations
around stability and a lot more users. In fact, Debian still ships
glibc 2.37, with some patches backported.

Now, on the other hand of the spectrum are Flávio's cross-hurd
scripts, which bootstrap a minimal Hurd-based system. These are small,
self-contained, and hackable. You can build the whole thing, including
the cross toolchains required, in a few minutes, without much of a
special setup required. Bumping glibc (or something) should be
trivial. If you want to contribute, you fork the Git repo, apply your
changes, and just open a PR. How cool is that?

So I think there is a place for some middle ground between the two: a
full (although small, "embedded") distro, with a package manager and
many available packages, that is at the same time easy to bootstrap,
to hack on, experiment with, and contribute to. The hackability should
hopefully ensure that this becomes a community project rather than a
one man show, and has a healthy bus factor.

I chose Alpine Linux as the upstream distribution for the project, for
various reasons; not least because I thought it would be a fun
endeavour to try and port Alpine which is known for not being a GNU
distro and in particular not using glibc (and it was!). Alpine
certainly fills the bill of being small and extremely hackable. They,
too, keep all of their package build definitions/scripts in a single
Git repo (aports); updating a package or adding a patch only requires
making an MR against the repo. The CI can then pick up the change,
rebuild the package, and without minutes of the MR being merged have
the new package available for download from the repo.

I have ported many Alpine packages to build with (i386, for now) GNU
Mach, the Hurd, and glibc, replacing Linux and musl. If you want a
specific number: as of yesterday, I have 299 installable packages; the
number of source packages is of course several times less than that.
Still, this includes things like curl, ncurses, nano, native binutils
& gcc & mig, libffi, openrc, openssl, util-linux, busybox, apk-tools,
... and of course gnumach, hurd (with dependencies like libdaemon,
parted, ...), and glibc. Importantly, all this cleanly bootstraps
using the scripts/bootstrap.sh script that they provide; this is too
somewhat like Flávio's scripts, but it uses the real full Alpine
package definitions for e.g. GCC (patched by me for glibc / Hurd
support).

Above the kernel and libc, things remain much as they were in upstream
Alpine: the system boots (will boot — I haven't tried it yet) with
busybox init & OpenRC, and uses busybox as its basic userland. GNU
software such as Bash is installable, too.

There is no ABI compatibility with either Alpine Linux or other Hurd

Re: [PATCH 03/14] add mach_host tests

2024-01-06 Thread Sergey Bugaev
On Sat, Jan 6, 2024 at 10:26 PM Luca  wrote:
> Uhm, I still have an issue, although a bit different now:
>
> By the way, the exception is still the same (General Protection, which
> is usually forwarded to user space), but for a different reason,
> apparently a non-canonical address in $rax=0x820175c0

I think this is just that you now have to add 2, not 1, to the result
of __builtin_frame_address().

Or better, do what I did in glibc, change it to an explicit function
argument [0], since __builtin_frame_address() doesn't return a useful
(for this purpose) value on aarch64.

[0]: 
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=24b707c1665afae7eb302542ffa92d53aa577111

Sergey



Re: [PATCH 03/14] add mach_host tests

2024-01-06 Thread Sergey Bugaev
On Sat, Jan 6, 2024 at 9:45 PM Samuel Thibault  wrote:
>
> Luca, le sam. 06 janv. 2024 19:41:17 +0100, a ecrit:
> > Il 29/12/23 15:14, Luca Dariz ha scritto:
> > > Il 29/12/23 14:44, Samuel Thibault ha scritto:
> > > > Also, it would be useful to compile the tests with
> > > > -ftrivial-auto-var-init=pattern so as to fill the structures with random
> > > > values before making the gnumach calls.
> >
> > with this option all tests fail on the first mig-generated stub entry, which
> > is task_get_special_port(), in _start(). Maybe it's related to SSE somehow,
> > I see a page fault here:
>
> Is $rbp unaligned?
>
> (we do want to fix such bug anyway)
>
> > (gdb) disassemble task_get_special_port
> > Dump of assembler code for function task_get_special_port:
> >0x00416bc6 <+0>:   push   %rbp
> >0x00416bc7 <+1>:   mov%rsp,%rbp
> >0x00416bca <+4>:   sub$0xa0,%rsp
> >0x00416bd1 <+11>:  mov%edi,-0x94(%rbp)
> >0x00416bd7 <+17>:  mov%esi,-0x98(%rbp)
> >0x00416bdd <+23>:  mov%rdx,-0xa0(%rbp)
> >0x00416be4 <+30>:  lea-0x60(%rbp),%rax
> >0x00416be8 <+34>:  movdqa 0x124f0(%rip),%xmm0# 0x4290e0
> > => 0x00416bf0 <+42>:  movaps %xmm0,(%rax)
> >0x00416bf3 <+45>:  movaps %xmm0,0x10(%rax)

Yes, you have to align the stack. An executable gets entered at _start
(or whatever the ELF header specifies) with %rsp 16-aligned, but you
must enter C code with %rsp being 8 modulo 8. To fix this, change your
_start like so:

asm(".global _start\n"
"_start:\n"
"  callq c_start");

void __attribute__((used, retain)) c_start()
{
...
}

This is only required on x86_64 (among the three architectures we care
about for now).

Sergey



Re: 64bit startup

2024-01-06 Thread Sergey Bugaev
On Sat, Jan 6, 2024 at 2:42 AM Luca  wrote:
> I had this small patch applied that apparently is enough for me to have
> some kind of core dump, I'm not sure if it's a good solution:

> +#ifdef __x86_64__
> +  struct _libc_fpstate fpstate;
> +  memset(, 0, sizeof(fpstate));
> +  note.data.pr_fpreg = 
> +#endif
> fetch_thread_regset (threads[i], _reg);
> fetch_thread_fpregset (threads[i], _fpreg);

Well, that should surely prevent the crash, but so will commenting out
the fetch_thread_fpregset call completely (perhaps this is what we
should actually do for the time being).

note.data is what we're writing out into the ELF core dump file; it
doesn't make any sense for it to be a pointer to a stack-allocated
variable in the dumper's address space. It doesn't make much sense for
it to be a pointer at all.

We need to figure out what kind of note GDB expects there to be, and
write that out. It doesn't necessarily have to match our definition of
fpregset_t; in fact I think it'd be better if builds of GDB without
any explicit support for x86_64-gnu would be able to read our core
files. And this means copying what Linux does, instead of apparently
Solaris, as the current elfcore tries to. Doing this might fix issues
with reading core files on i686-gnu, too.

> sure, I've started looking into it,

\o/

> but it will take a while before I
> can run something in userspace.

Sure, I don't expect you to produce a working kernel overnight :)

I kind of want to participate in kernel-side hacking too, but I don't
nearly have the understanding required.

How does initial boot protocol work, for example? I mean, where and
how control is transferred, what gets passed in registers, that kind
of thing. I've found many detailed explanations of board-specific boot
details (e.g. for Raspberry Pi 3), and [0] has a nice explanation of
how to make U-Boot load a custom kernel instead of Linux. I haven't
been able to find much info on GRUB; it sounds like Multiboot still
exists on AArch64, but it's unclear exactly how it works.

[0]: https://krinkinmu.github.io/2023/08/21/how-u-boot-loads-linux-kernel.html

Then, we're supposed to parse & use the device tree, aren't we? Do I
understand it right that both Mach and userland would have to deal
with the device tree? — in case of Mach, this would be needed to get
info on CPU cores, RAM, and serial / console / UART, right?

Do the questions at least make sense? Or am I talking nonsense? Can
you recommend any useful resources?

Are you targeting (or: do you think it's realistic to target) many
platforms / boards in a generic manner, or would we have to have
platform-specific gnumach builds? Does it make sense to start with
some specific platform (qemu "virt"?), and expand from there, or is it
better to build in the genericity from the start?

Sergey



Re: 64bit startup

2024-01-05 Thread Sergey Bugaev
I'm not seeing hurd-dbg / hurd-libs-dbg packages in your repo. Could
you please either teach me where to look, or if they're indeed
missing, upload them?

Also I can't help but notice that the hurd package (i.e the translator
binaries) is still not being built as PIE, unlike basically all the
other binaries. This actually helps with debugging for now, but please
remember to ensure it does end up as PIE when the system is ready for
broader use.

/servers/crash-dump-core crashes on the memset () call in
hurd:exec/elfcore.c:fetch_thread_fpregset (); the (*fpregs) pointer is
NULL. The caller passes fpregs = _fpreg, where note.data
is of type struct elf_lwpstatus, defined in hurd:include/sys/procfs.h,
whose pr_fpreg field is of type prfpregset_t, which is a typedef to
fpregset_t, which was an actual struct on i386, but is a pointer on
x86_64. This would've been easier to debug if I had debuginfo :)

Sergey



Re: TODO-list

2024-01-05 Thread Sergey Bugaev
On Fri, Jan 5, 2024 at 2:09 AM Samuel Thibault  wrote:
> This is a TODO-list of mostly not-sexy things, but that we do want to
> work on, because at some point it can be a question of survival of the
> whole Hurd ecosystem (e.g. y2038 really is a concern).

You may want to add moving off ext2 to something more modern that can
store post-2038 timestamps to the list.

Sergey



Re: 64bit startup

2024-01-05 Thread Sergey Bugaev
On Fri, Jan 5, 2024 at 12:52 AM Samuel Thibault  wrote:
> Which kind of activity?

I just had a loop spawning /bin/true — this should've triggered it
assuming it was related to some state getting corrupted on
context-switching.

> I use
>
> while true ; do apt install --reinstall wdiff ; done

That did it! I can now reliably reproduce this.

(I assume you don't mind my box constantly banging on your repo.)

> got acd :)

In the six times that I've reproduced it so far, I got "acd" in all cases. Hmmm.

Sergey



Re: 64bit startup

2024-01-04 Thread Sergey Bugaev
On Thu, Jan 4, 2024 at 10:57 AM Samuel Thibault  wrote:
>
> Sergey Bugaev, le mer. 03 janv. 2024 21:56:54 +0300, a ecrit:
> > perhaps I need to try two of them in parallel and some I/O-heavy
> > workload in the background, as you're saying.
>
> Yes, that's needed to raise the probability of the bug.

I'm still unable to reproduce this, it's been running for 10+ hours at
this point. That's two copies of it, and unrelated activity in the
background.

> > Could it be that the two strings are actually different (something
> > being wrong with pipes perhaps)?
>
> I tried
>
> A=a ; time while /usr/bin/\[ "$A" = a ] ; do A="$(echo -n `echo a` )" ; done 
> ; echo $A
>
> The output is empty. But yes, that could be some missing flush or such
> in pipes.

Try

A=abcd ; time while /usr/bin/\[ "$A" = abcd ] ; do A="$(echo -n `echo
a``echo b`)$(echo -n `echo c``echo d`)" ; done ; echo $A

perhaps?

Sergey



Re: 64bit startup

2024-01-04 Thread Sergey Bugaev
On Wed, Jan 3, 2024 at 10:07 PM Luca  wrote:
> Hi Sergey,

Hi,

> Recently I've been installing hurd-amd64 on another disk of my hurd-i386
> vm and booting from that. Basically I prepare the disk with debootstrap
> --foreign, then I reuse the i386 grub install to boot the 64 bit kernel
> with a custom entry,

That (debootstrap + reusing existing GRUB from the i686 installation)
is what I was doing, yes, in one of the two setups that I've tried. On
the other (on a different host) I was doing grub2-install myself. In
both cases I got the same result, with GRUB working fine, but then
rumpdisk apparently misbehaving.

I could reproduce this if we want to debug it further, but Samuel's
image works great for now.

> then run the --second stage, configure login, fstab
> and network and reboot. I can give you the exact commands and setup I'm
> using if you want (I need to reinstall it anyway due to latest changes),
>
> I'm currently using qemu via virt-manager, mostly with the default
> configuration for an x86_64 vm; that means a virtual SATA disk
> controller and Q35 chipset.

Yes, I'd like to use libvirt eventually too, like I'm doing for my
i686 Hurd VM. But I need greater control over how I invoke QEMU for
now.

Sergey

P.S. I have posted all of my patches, so if you're interested in
hacking on aarch64-gnu Mach, you should be able to build the full
toolchain now.



Re: [PATCH 01/23] hurd: Add some missing includes

2024-01-03 Thread Sergey Bugaev
On Thu, Jan 4, 2024 at 12:08 AM Sergey Bugaev  wrote:
> This is testing installed headers, isn't it? — then
> how come sysdeps/hurd/include/hurd.h is what gets found for ?
> I'm rather sure the installed  is a different file. So it
> would look like the test setup is broken, and this patch just exposes
> that.

Should the include  be guarded by ifndef _ISOMAC perhaps? And
if we indeed move the inline functions to the internal hurd.h, they'd
also be guarded by ifndef _ISOMAC?

But really, why doesn't the test filter out the internal include directories?

Sergey



Re: [PATCH 01/23] hurd: Add some missing includes

2024-01-03 Thread Sergey Bugaev
On Wed, Jan 3, 2024 at 11:43 PM Samuel Thibault  wrote:
> Sergey Bugaev, le mer. 03 janv. 2024 20:14:34 +0300, a ecrit:
> > diff --git a/sysdeps/hurd/include/hurd.h b/sysdeps/hurd/include/hurd.h
> > index 568092d6..189fd44e 100644
> > --- a/sysdeps/hurd/include/hurd.h
> > +++ b/sysdeps/hurd/include/hurd.h
> > @@ -1,4 +1,5 @@
> >  #ifndef  _HURD_H
> > +#include 
> >  #include_next 
> >
> >  void _hurd_libc_proc_init (char **argv);
> > diff --git a/sysdeps/hurd/include/hurd/signal.h 
> > b/sysdeps/hurd/include/hurd/signal.h
> > index 1dc8a1f3..9b1bf3df 100644
> > --- a/sysdeps/hurd/include/hurd/signal.h
> > +++ b/sysdeps/hurd/include/hurd/signal.h
> > @@ -6,6 +6,7 @@ extern struct hurd_sigstate *_hurd_self_sigstate (void) 
> > __attribute__ ((__const_
> >  libc_hidden_proto (_hurd_self_sigstate)
> >  #endif
> >
> > +#include 
> >  #include_next 
> >
> >  #ifndef _ISOMAC
>
> Why?

Because hurd/hurd/signal.h is using tls.h macros (THREAD_GETMEM /
THREAD_SETMEM / THREAD_SELF), guarded under "defined _LIBC", and
sysdeps/hurd/include/hurd/signal.h being the internal version of that
header seemed to be the appropriate place to add the missing #include
. Otherwise, I get this:

In file included from ../sysdeps/hurd/include/hurd/signal.h:9,
 from siginfo.c:18:
../hurd/hurd/signal.h: In function ‘_hurd_self_sigstate’:
../hurd/hurd/signal.h:169:30: error: implicit declaration of function
‘THREAD_GETMEM’ [-Wimplicit-function-declaration]
  169 |   struct hurd_sigstate *ss = THREAD_GETMEM (THREAD_SELF,
_hurd_sigstate);

and so on. This must have happened to work on both x86 architectures
due to some other header implicitly pulling  in, but we should
not rely on that.

Perhaps a better solution would be to move the inline versions of
_hurd_self_sigstate and _hurd_critical_section_lock/unlock to the
internal header. Is there any reason why they have to be in the public
one?

> These are breaking hurd/check-installed-headers-c

Indeed, thanks for pointing that out. But the error I seem to get:

:: hurd.h

In file included from ../sysdeps/unix/i386/sysdep.h:18,
 from ../sysdeps/mach/x86/sysdep.h:47,
 from ../sysdeps/mach/hurd/tls.h:27,
 from ../sysdeps/mach/hurd/i386/tls.h:24,
 from ../sysdeps/hurd/include/hurd.h:2,
 from /tmp/cih_test_z99fCI.c:10:
../sysdeps/unix/sysdep.h:111:5: error: "IS_IN" is not defined,
evaluates to 0 [-Werror=undef]
  111 | #if IS_IN (rtld)
  | ^
../sysdeps/unix/sysdep.h:111:11: error: missing binary operator before token "("
  111 | #if IS_IN (rtld)
  |   ^
../sysdeps/mach/hurd/i386/tls.h:123:32: error: missing binary operator
before token "("
  123 | #if !defined (SHARED) || IS_IN (rtld)
  |^
../sysdeps/mach/hurd/i386/tls.h: In function ‘_hurd_tls_fork’:
../sysdeps/mach/hurd/i386/tls.h:379:3: error: unknown type name ‘error_t’
  379 |   error_t err;
  |   ^~~

...makes no sense. This is testing installed headers, isn't it? — then
how come sysdeps/hurd/include/hurd.h is what gets found for ?
I'm rather sure the installed  is a different file. So it
would look like the test setup is broken, and this patch just exposes
that.

Sergey



Re: 64bit startup

2024-01-03 Thread Sergey Bugaev
On Wed, Jan 3, 2024 at 11:27 AM Samuel Thibault  wrote:
> Sergey Bugaev, le mer. 03 janv. 2024 11:17:53 +0300, a ecrit:
> > I guess this is where I ask (consistent with the subject line) about
> > how I would run the x86_64 system (to reproduce & debug this).
>
> You probably want to start with the pre-built images I have linked from
> the wiki page.

Ah... I have been reading the wrong version of the wiki page again. It
doesn't help that there are many of them [0][1][2][3].

[0] https://www.gnu.org/software/hurd/faq/64-bit.html
[1] https://www.gnu.org/software/hurd/open_issues/64-bit_port.html
[2] https://darnassus.sceen.net/~hurd-web/faq/64-bit/
[3] https://darnassus.sceen.net/~hurd-web/open_issues/64-bit_port/

But your disk image works *great*! \o/ I don't know what is different
compared to what I was trying, but yours just works.

I haven't been able to reproduce your bug in a few hours of testing;
perhaps I need to try two of them in parallel and some I/O-heavy
workload in the background, as you're saying. Even if I do manage to
reproduce this, I don't immediately know how to debug it; maybe we
could try to use qemu's record/replay functionality to debug it
backwards from where we can detect it? (I have found the rr(1) tool
*immensely* useful for debugging GTK issues.)

Could it be that the two strings are actually different (something
being wrong with pipes perhaps)?

Sergey



Re: [RFC PATCH 00/23] aarch64-gnu port

2024-01-03 Thread Sergey Bugaev
On Wed, Jan 3, 2024 at 8:30 PM Joseph Myers  wrote:
> I think the same principle applies for ports to new (architecture, Hurd)
> pairs as for new (architecture, Linux) pairs: the relevant code needs to
> be in upstream mainline of all components on which glibc build-depends
> before the port can go into glibc (and thus before the symbol versions for
> the port can be determined) - and at the point where it's ready to go in,
> a corresponding build-many-glibcs.py entry should be added as part of the
> patch series.  Parts of  may
> be applicable, though that's more oriented to the case where the
> architecture support itself is entirely new.
>
> You can of course do refactors of existing files not specific to
> aarch64-gnu, in preparation for the port, before then, to reduce the size
> of the eventual patch series proposing adding the port to glibc.

Certainly; and I should've been more clear about this: I don't expect
this to get merged until there's a gnumach port. And the port
development, and the feedback I'm hoping to get, will likely require
changes/tweaks to the Mach headers/APIs (as I've said, my versions
I've developed this against are more like preliminary sketches than
final APIs set in stone) and the corresponding changes to this port,
so I don't expect it to be merged until that all is settled.

Some generic improvements could be merged now as you're saying, but
other than that, I'm posting these patches both to gather feedback
from both Hurd and glibc communities, and to enable others to build
it, experiment with it, and build more stuff on top of it (for
example, can we get all of the Hurd building?). Symbol versions, I
have set to 2.39, but seeing how the 2.39 release is already in
progress, we'll likely need to bump this.

Sergey



  1   2   3   4   5   6   7   8   >