Re: [RFC PATCH] Adding RTC device (work in progress)

2024-11-09 Thread Sergey Bugaev
On Fri, Nov 8, 2024 at 3:26 AM Zhaoming Luo  wrote:
> The rest of the stuff
> is mainly about filling codes into the server-side functions; it may
> require some time as I haven't had any experience of writing drivers.

Me neither :) But, perhaps the following would be somewhat useful.

The osdev wiki has articles about RTC [0] and CMOS [1]; looks like one
can access them pretty easily with 'in'/'out' on ports 0x70 and 0x71.
The SerenityOS driver [2][3][4] seems to match the osdev articles
well; it must have been written using them as a reference.

[0]: https://wiki.osdev.org/RTC
[1]: https://wiki.osdev.org/CMOS
[2]: 
https://github.com/SerenityOS/serenity/blob/master/Kernel/Arch/x86_64/Time/RTC.cpp
[3]: 
https://github.com/SerenityOS/serenity/blob/master/Kernel/Arch/x86_64/RTC.cpp
[4]: 
https://github.com/SerenityOS/serenity/blob/master/Kernel/Arch/x86_64/CMOS.cpp

To enable your process to use 'in' & 'out', you have to call ioperm
(), I believe — which on the Hurd is implemented via the
i386_io_perm_create and i386_io_perm_modify gnumach RPCs; this
requires having access to the device master port, i.e. being root. You
should then be able to use inb/outb functions from sys/io.h (or
perhaps their _p versions?)

This seems to be the QEMU-side implementation:
https://gitlab.com/qemu-project/qemu/-/blob/master/hw/rtc/mc146818rtc.c

All of this is specific to x86 and/or "PC" (or rather: "Motorola
MC146818"?); the Linux doc [5] talks about the "old PC/AT-Compatible
driver: /dev/rtc" and "new portable “RTC Class” drivers: /dev/rtcN".
Perhaps this should be taken into consideration? It's completely fine
to only support the x86/PC RTC for now, but let's make sure we end up
with a design that allows us to support other platforms (ARM, RISC-V)
in the future.

[5] https://docs.kernel.org/admin-guide/rtc.html

I know that RTC can be configured to either represent local time, or
in UTC. MS Windows prefers the former, GNU/Linux (or rather systemd?)
prefers the latter [6]. Would it maybe make sense for the driver to
have an --option to *pretend* the RTC stores UTC time when it's
actually storing local time, transparently converting the time on
read/write? The driver would learn the local timezone the same way all
processes do (tzset?).

[6]: https://wiki.archlinux.org/title/System_time

Sergey



Re: [RFC PATCH v2 4/4] Add rtc server

2024-11-08 Thread Sergey Bugaev
On Fri, Nov 8, 2024 at 4:55 AM Zhaoming Luo  wrote:
> diff --git a/rtc/main.c b/rtc/main.c
> new file mode 100644
> index ..114fb497
> --- /dev/null
> +++ b/rtc/main.c
> @@ -0,0 +1,88 @@
> +
> +#include 
> +
> +#include 
> +#include 
> +#include 

I don't think you need nullauth.h?

> +#include 
> +#include 
> +#include 
> +
> +#include "rtc_pioctl_S.h"
> +
> +const char *argp_program_version = STANDARD_HURD_VERSION (rtc);
> +
> +struct trivfs_control *rtccntl;

Please make global variables 'static' unless there is a reason not to.

> +int trivfs_fstype = FSTYPE_DEV;
> +int trivfs_fsid = 0;
> +int trivfs_support_read = 0;

Actually Linux lets you read() /dev/rtc, doesn't it?

> +int trivfs_support_write = 0;
> +int trivfs_support_exec = 0;
> +int trivfs_allow_open = O_READ | O_WRITE;
> +
> +static const struct argp_option options[] =
> +{
> +  {0}
> +};
> +
> +/* TODO: adding option */

Hm, so what kind of options do you envision it might have? (Not saying
there's none, just wondering.)

Can there be multiple RTC devices? (the Linux man page talks of
"/dev/rtc0, /dev/rtc1, etc."). Do we need a way to identify which
specific RTC device the translator should drive?

> +static error_t
> +parse_opt (int opt, char *arg, struct argp_state *state)
> +{
> +  return ARGP_ERR_UNKNOWN;
> +}
> +
> +static const struct argp rtc_argp =
> +{ options, parse_opt, 0, "RTC device" };
> +
> +int
> +demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)

Same here, make it 'static' please, unless there is a reason not to.

> +{
> +  mig_routine_t routine;
> +  if ((routine = rtc_pioctl_server_routine (inp)) ||
> +  (routine = NULL, trivfs_demuxer (inp, outp)))
> +{
> +  if (routine)
> +(*routine) (inp, outp);
> +  return TRUE;
> +}
> +  else
> +return FALSE;
> +}
> +
> +int
> +main (int argc, char **argv)
> +{
> +  error_t err;
> +  mach_port_t bootstrap;
> +
> +  argp_parse (&rtc_argp, argc, argv, 0, 0, 0);
> +
> +  task_get_bootstrap_port (mach_task_self (), &bootstrap);
> +  if (bootstrap == MACH_PORT_NULL)
> +error (1, 0, "Must be started as a translator");
> +
> +  /* Reply to our parent */
> +  err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &rtccntl);

Even more of a nitpick: better pass NULL instead of 0 when the type is
a pointer. So:

trivfs_startup (bootstrap, 0, NULL, NULL, NULL, NULL, &rtccntl)

you might even specify the first 0 as O_NORW for clarity, but I
haven't seen anyone do that.

> diff --git a/rtc/pioctl-ops.c b/rtc/pioctl-ops.c
> new file mode 100644
> index ..44038e26
> --- /dev/null
> +++ b/rtc/pioctl-ops.c
> @@ -0,0 +1,28 @@
> +/* Server side implementation for rtc device */
> +
> +/* This implementation is largely based on sys-utils/hwclock from util-linux 
> */
> +
> +#include "rtc_pioctl_S.h"
> +#include 
> +#include 
> +
> +/* 9 RTC_RD_TIME -- Read RTC time */
> +kern_return_t
> +rtc_S_pioctl_rtc_rd_time (struct trivfs_protid *cred, struct rtc_time *time)
> +{
> +  if (!cred) {
> +return EOPNOTSUPP;
> +  }

Nitpick: according to the GNU C style, this pair of braces shouldn't be here.

> +  if (!(cred->po->openmodes & O_READ))
> +return EBADF;
> +  return KERN_SUCCESS;
> +}
> +
> +/* 10 RTC_SET_TIME -- Set RTC time */
> +kern_return_t
> +rtc_S_pioctl_rtc_set_time (struct trivfs_protid *cred, struct rtc_time time)
> +{
> +  if (!(cred->po->openmodes & O_WRITE))
> +return EBADF;

You need to check for cred being NULL here too, before you dereference it.

Again, this happens when the request arrives on some port that we
listen for messages on, but it corresponds to something other than a
protid, e.g. the trivfs control port. EOPNOTSUPP is the appropriate
error code to return in that case, because indeed the
whatever-other-kind of port doesn't support the ioctl, only protids
do.

> +  return KERN_SUCCESS;
> +}

Sergey



Re: [RFC PATCH v2 2/4] Add ioctl interface for rtc device

2024-11-08 Thread Sergey Bugaev
Hi Zhaoming,

On Fri, Nov 8, 2024 at 11:01 AM Samuel Thibault  wrote:
> Here as well this breaks the build since at this point of the series you
> haven't added rtc.h yet. Better just merge all the patches.

To expand on what Samuel says, the point is that the repo is expected
to build successfully if you check out any specific Git commit. This
is helpful for using 'git bisect' in particular to catch regressions
[0], but is also generally a good practice. You might call it a part
of Git hygiene.

[0] which now that I'm typing this doesn't sound like a good enough
reason to go through the pain of ensuring that every single commit
builds...

So not only are you expected to split your diff into a set of
reasonably-sized, self-sufficient, reviewable patches; you should also
consider the dependencies between your changes, and commit them in the
right order.

If you're adding an entire new component, like the new server here,
and it is reasonably small, it makes sense to just do the whole thing
in a single patch. But if you were adding a large new subsystem to
Linux for example, you could be asked to split it into individual
patches, so it could be reviewed step-by-step, while still keeping
each of those steps functional (i.e. at least building successfully).
You might add just the bare essentials/stubs which are enough to build
*something* in the first patch for example, and then keep adding
functionality in subsequent patches.

But for your case here, you can just squash the patches into one.

Sergey



Re: [RFC PATCH] Adding RTC device (work in progress)

2024-11-07 Thread Sergey Bugaev
On Wed, Nov 6, 2024 at 4:28 AM Zhaoming Luo  wrote:
> I think it's worth to put this part into mig documentation website[0],
> just like the IRC log pieces we have already had. What do you think? I
> can do it.
>
> [0]:
> https://darnassus.sceen.net/~hurd-web/microkernel/mach/mig/documentation/

Sure, if you think it'd be useful, I don't mind. Was the explanation
clear enough / do you have follow-up questions?

Have you made any progress on the RTC server?

Sergey



Re: [RFC PATCH] Adding RTC device (work in progress)

2024-11-05 Thread Sergey Bugaev
On Sun, Nov 3, 2024 at 11:19 AM Zhaoming Luo  wrote:
> >> +import "rtc.h";
> > This would only work when the generated C file is built in the rtc/ of
> > the Hurd source tree, right? Perhaps this should be ?
> It makes sense, and I have corrected it. However, then the compilation
> will fail with:
> ```
> make[2]: *** No rule to make target 'hurd/rtc/rtc.h', needed by
> 'main.o'.  Stop.
> ```
> If I want to fix it. Do I need to modify $(hurd)/rtc/Makefile or add
> hurd/rtc/rtc.h into hurd-dev package?

Uhh. I actually have very little idea how to do this properly.

For one thing it should probably be just  rather than
? You could maybe then place the file into hurd/rtc.h,
next to hurd/pioctl.defs.

Alternatively, if you do want to keep the header in the rtc/
subdirectory of the source tree, you'd have to duplicate some of the
logic that the buildsystem has for the "library" mode. Maybe something
like this would work:

install: $(DESTDIR)$(includedir)/hurd/rtc.h
install-headers: $(DESTDIR)$(includedir)/hurd/rtc.h

$(DESTDIR)$(includedir)/hurd/rtc.h: rtc.h
$(INSTALL_DATA) $< $@

include/hurd/rtc.h:
echo '#include "../rtc/rtc.h"' > $@

Samuel would have a much better idea than me about how this should be
done properly.

> >> diff --git a/rtc/mig-mutate.h b/rtc/mig-mutate.h
> >> new file mode 100644
> >> index ..e69de29b
> > You'd want to put something like the following into this file:
> >
> > #define IO_INTRAN trivfs_protid_t trivfs_begin_using_protid (io_t)
> > #define IO_INTRAN_PAYLOAD trivfs_protid_t trivfs_begin_using_protid_payload
> > #define IO_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t)
> > #define IO_IMPORTS import "libtrivfs/mig-decls.h";
> >
> > ...and change 'io_t reqport' arguments in pioctl-ops.c to 'struct
> > trivfs_protid *cred'.
> I just know that this is the process of transforming the parameter type
> so we can have different parameter types on server side and user side.
> Is there some document explaining how to write a mig-mutate.h file? I
> haven't found one.

...but at least this I can hopefully answer :)

I don't think there's proper documentation anywhere about all of this.
Things are very underdocumented, as you must have already realized.

First, a brief description of what a protid is. Hurd translators
typically represent "files" internally with three kinds of distinct
structures:

1. node -- these are filesystem nodes, same concept as an "inode".
2. peropen -- this keeps the data "per open" of the file and
corresponds to an "open file description" in POSIX. Things like
current I/O offset and the open mode (O_READ | O_WRITE ...) live here.
3. protid (or "credential") -- describes a specific "user" (UIDs/GIDs)
on behalf of whom the file is being accessed.

A protid has a pointer to the peropen, and the peropen has a pointer
to the node. A node can have multiple peropens referring to it (when
the file has been opened multiple times), and a peropen can have
multiple protids referring to it (when processes running as different
users share an open file description, e.g. your shell and a sudo
invocation share the pts). In trivfs, there's only a single node, so
the concept is deemphasized.

The concept of protid doesn't exist in classic Unix, since a
monolithic kernel can just directly see which UID the current process
runs as. But Mach IPC is (intentionally) designed in a way that it's
inherently impossible to see "who's asking", so instead we represent
differently-privileged callers with different handles (protids) that
refer to the same peropen, and then we check which protid the request
was made on.

It is a protid that corresponds to an Mach port (io_t, file_t, ...),
though the client side doesn't need to care.

When an incoming request arrives, the thing you actually receive in a
message is the port name (ignoring protected payloads for now). What
you actually want is the protid that it corresponds to.

trivfs has the API to look up the protid given the port, namely
trivfs_begin_using_protid (which wraps ports_lookup_port from
libports), and you could call that yourself:

kern_return_t
rtc_S_foobar (io_t port, int foo, int *bar)
{
  error_t err = 0;
  struct trivfs_protid *cred = trivfs_begin_using_protid (port);

  if (!cred)
/* The request came in on a port that we listen for incoming
 * messages on, but it doesn't correspond to a protid. Must
 * be some other kind of port. */
return EOPNOTSUPP;

  if (!(cred->po->openmodes & O_READ))
{
  err = EBADF;
  goto out;
}

  do something with cred...

out:
  trivfs_end_using_protid (cred);
  return err;
}

But since we already have a code generator (MIG), why not make it
generate the conversion logic for us as well. And so, in MIG, when
defining a type, you can provide 'intran' and 'outtran' and
'destructor' function names, and MIG will generate the calls for you.

So the proper MIG way to (but see below about the Hurd way) to do the
thing that you're trying to do would b

Re: [RFC: drm server] limitations of MiG for ioctls

2024-11-05 Thread Sergey Bugaev
On Tue, Nov 5, 2024 at 10:16 AM Yuqian Yang  wrote:
> > 1. the ioctl ID encoding space is fully used already -- all the bits
> > in an ioctl ID are meaningful, so there'd be nowhere to pack the new
> > info;
>
> What does this mean? So we can't create new ioctl op and args for drm
> with the same value in Linux?

It has to do with how ioctls are implemented on the Hurd (in glibc). I
went into some more details about this in the other thread (about
RTC), but basically since glibc doesn't want to statically contain
knowledge of all the possible ioctls and their argument types, instead
the info about argument types of an ioctl is encoded directly into the
ioctl number (aka ID, op). So the IDs are not random and contain info
about the ioctl they identify; and this means that you cannot just
pick any (otherwise unused) ID for an ioctl -- the ID has to match the
ioctl's arguments.

And one of the reasons that we can't extend the ioctl mechanism to
support the more advanced operations wrt memory buffers that Damien
needs is that for that, we would have to come up with a way to encode
this new info into the ioctl ID as well, but we cannot, since all the
individual bits of the 32-bit ID type are already used.

But also see what Samuel says about _HURD_HANDLE_IOCTL -- I completely
forgot about that.

> It is not only drm_version but a lot of structs.
>
> All in all, we have to patch on libdrm, anyway. How about we make a
> patch in libdrm? Wrap ioctl with real implementation for Mach and Hurd
> (by passing real data in RPC instead of nonsense pointers) and preserve
> the behavior that libdrm expects. And at the same time, solve the
> problem of using particular ioctl op and args that is conflict with
> existing value. Or do you have some ideas on this?

I have not looked into libdrm so this might be entirely wrong (or
naive, as azert says), but I was imagining libdrm basically wraps the
ioctls into C functions, like

int drmFooBar(int fd, int a, int b) {
struct drm_foo_bar arg { a, b };
return ioctl(fd, DRM_FOO_BAR, &arg);
}

and we'd instead make it into

#ifndef __GNU__
the above...
#else
int drmFooBar(int fd, int a, int b) {
return HURD_DPORT_USE(fd, drm_foo_bar(port, a, b));
}
#endif

or more likely these would be in separate files rather than ifdef'ed,
but you get the idea.

If that's not what libdrm does? or is it unfeasible to have separate
versions for Linux and Hurd like that?

Sergey



Re: [RFC: drm server] limitations of MiG for ioctls

2024-11-04 Thread Sergey Bugaev
On Mon, Nov 4, 2024 at 10:44 AM Damien Zammit wrote:
> I am currently attempting to implement a drm server to provide
> a way to use libdrm with multiboot framebuffer exposed by new device(mbinfo).
>
> I am running into a problem that I am unable to implement a compatible
> ioctl api because of the layout of the structures.

Thanks for writing this down. I will repeat the same things I said on IRC:

> I would prefer to reuse the same api as drm ioctls rather than implement
> a modified version using traditional RPCs with many arguments.
> This is because libdrm would need to be modified substantially and I don't 
> want
> to clutter the client with more parameters and conditional code.

I understand that motivation, but the requirements about more complex
structs that you describe below are really not compatible with how MIG
structs -- or glibc/Hurd ioctls -- can be used.

> The main problem is that a few of the OUT ioctls expect the server to copy 
> data
> through the RPC, and MiG is confused by nested structs, it doesn't seem to
> support something like:
>
> type drm_version_t = struct {
> int foo;
> int bar_length;
> data_t bar;
> };

As mentioned on IRC, I'm surprised this doesn't immediately produce an
error. The logic for that seems to be in place:

if (!t->itInLine) {
error("Type %s must be inline\n", $2);
}

Other than the error that should be there but isn't, it cannot work,
since these C-like structs are still desugared to classic structs,
i.e. just small fixed-size arrays of integers. Such a structure still
generates a single "data element" in a message body.

> You _can_ specify individual parameters in the routine like so:
>
> routine drm_version (
> port: drm_t;
> foo: int;
> out bar: data_t SCP);
>
> but then the bar_length parameter comes AFTER the bar parameter,
> and has type unsigned int, (not int),

That's the way it works -- an array parameter in MIG defs maps to a
pointer + size pair in C, and size is of type mach_msg_type_number_t.

This is the part that could be tweaked most easily, if there was a
real need -- we could add a new MIG option or something. But I don't
think it would actually help much with your use case.

> and you cannot seem to pack the whole thing
> into a struct compatible with an ioctl like:
>
> routine drm_version (
> port: drm_t;
> out bar: drm_version_t);

Yes, so none of this would work with ioctls at all. ioctls support
passing (small arrays of) basic integer types in and out, which is
again enough for simple structures. And indeed basic integer types and
simple structures are what ioctls work on, traditionally, on Unix.

It is not feasible to extend the ioctls mechanism for passing OOL
memory, because:

1. the ioctl ID encoding space is fully used already -- all the bits
in an ioctl ID are meaningful, so there'd be nowhere to pack the new
info;

2. where would the received pointer point? -- in other words, where
would the received data go? In Mach IPC, the received OOL data (or
port arrays) just appears as new pages somewhere in the receiver's
address space (vm_map). In Unix APIs something like that never
happens; the caller always has to provide its own buffer that the data
gets written over. Compare Hurd's io_read vs Unix read for example.

So in your case, it's likely that the caller has to provide, as input
to the ioctl, a pointer to where it would like the 'data_t bar' to be
written out to, and then Linux would write the actual 'bar' data into
the pointed-to memory. And 'bar_length' is likely in-out, signifying
the buffer length on 'in', and the used length on 'out'. Right?

It is very possible to implement this behavior on top of MIG routines.
But it is way too complex to try and support this in ioctls. We would
need to somehow encode where in the structure the size and the pointer
are... No, this just can't happen.

> How do I solve this?  Can we extend MiG to be smarter about nested structures 
> when
> data needs to be transferred within structs?  How do we solve the ordering 
> problem of
> the *_length parameter?

At least for the calls that have more complex behavior wrt memory (and
not just passing bundles of integers), don't try to make them into
ioctls, make them real full MIG routines, and use them as such from
the client side. Is it just drm_version? If so, perhaps it could just
always return some hardcoded values client-side, without making any
RPCs at all.

Sergey



Re: [RFC PATCH] Adding RTC device (work in progress)

2024-11-01 Thread Sergey Bugaev
On Fri, Nov 1, 2024 at 2:46 PM Zhaoming Luo  wrote:
> diff --git a/hurd/pioctl.defs b/hurd/pioctl.defs
> new file mode 100644
> index ..36fa8d3f
> --- /dev/null
> +++ b/hurd/pioctl.defs
> @@ -0,0 +1,34 @@
> +/* Definitions for /dev/rtc ioctls */
> +
> +/* Ioctl group 'p'; the subsystem is derived from calculations in
> +   hurd/ioctls.defs. */
> +subsystem pioctl 14;
> +
> +#include 
> +
> +import "rtc.h";

This would only work when the generated C file is built in the rtc/ of
the Hurd source tree, right? Perhaps this should be ?

Do I understand it right that pioctl.defs *is* supposed to be
installed onto the target machine (in some sort of hurd-dev package),
as opposed to being a private implementation detail of the RTC server?

> +int
> +demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
> +{
> +  mig_routine_t routine;
> +  if ((routine = rtc_pioctl_server_routine (inp)) ||
> +  (routine = NULL, trivfs_demuxer (inp, outp)))
> +{
> +  if (routine)
> +(*routine) (inp, outp);
> +  return TRUE;
> +}
> +  else
> +return FALSE;
> +}

Ack, the demuxer looks good.

> +
> +int
> +main (int argc, char **argv)
> +{
> +  error_t err;
> +  mach_port_t bootstrap;
> +
> +  mach_port_allocate (mach_task_self (),
> + MACH_PORT_RIGHT_RECEIVE, &fsys_identity);

I don't think you need this (nor the global variable) for anything.
libtrivfs already makes a fsys_id port that it uses in
trivfs_S_io_identity.

> +  argp_parse (&rtc_argp, argc, argv, 0, 0, 0);
> +
> +  task_get_bootstrap_port (mach_task_self (), &bootstrap);
> +  if (bootstrap == MACH_PORT_NULL)
> +error(1, 0, "Must be started as a translator");
> +
> +  /* Reply to our parent */
> +  err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &rtccntl);
> +  mach_port_deallocate (mach_task_self (), bootstrap);
> +  if (err)
> +return -1;

Rather, error (1, err, "trivfs_startup failed"). You can pick a
different exit code from 1, of course, but -1 is not a great code to
return from main.

> diff --git a/rtc/mig-mutate.h b/rtc/mig-mutate.h
> new file mode 100644
> index ..e69de29b

You'd want to put something like the following into this file:

#define IO_INTRAN trivfs_protid_t trivfs_begin_using_protid (io_t)
#define IO_INTRAN_PAYLOAD trivfs_protid_t trivfs_begin_using_protid_payload
#define IO_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t)
#define IO_IMPORTS import "libtrivfs/mig-decls.h";

...and change 'io_t reqport' arguments in pioctl-ops.c to 'struct
trivfs_protid *cred'.

> diff --git a/rtc/pioctl-ops.c b/rtc/pioctl-ops.c
> new file mode 100644
> index ..02f4c65f
> --- /dev/null
> +++ b/rtc/pioctl-ops.c
> @@ -0,0 +1,17 @@
> +#include "rtc_pioctl_S.h"
> +#include "rtc.h"
> +#include 
> +
> +/* 9 RTC_RD_TIME -- Read RTC time*/
> +kern_return_t
> +rtc_S_pioctl_rtc_rd_time (io_t reqport, struct rtc_time * time)
> +{
> +  return KERN_SUCCESS;
> +}

So this should start by doing something like:

if (!cred)
  return EOPNOTSUPP;
if (!(cred->po->openmodes & O_READ))
  return EBADF;

> +
> +/* 10 RTC_SET_TIME -- Set RTC time*/
> +kern_return_t
> +rtc_S_pioctl_rtc_set_time (io_t reqport, struct rtc_time time)
> +{
> +  return KERN_SUCCESS;
> +}

and this would check for O_WRITE then.

Sergey



Re: [RFC PATCH 0/3] Adding /dev/rtc device (work in progress)

2024-11-01 Thread Sergey Bugaev
On Fri, Nov 1, 2024 at 1:46 PM Zhaoming Luo  wrote:
> Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): y
> 250 OK
>  ...propagated at /usr/lib/git-core/git-send-email line 1696, 
> line 2.

Hm, I have no idea about this kind of thing. git-send-email line 1696
in my copy of Git v2.47.0 is just

$smtp->mail( $raw_from ) or die $smtp->message;

The code (and the man page) mentions --smtp-debug, perhaps that would
help? You could try using a different email server to see if this is
specific to yours (qq.com)? But please experiment with a 'to' address
that's not this whole list; try sending the patches to yourself, or to
Drew's ~sircmpwn/email-test-dr...@lists.sr.ht from the tutorial.

For now, maybe you could just concatenate (i.e. 'cat') the patches
together and send them as a single message, so we can proceed with
reviewing them.

Sergey



Re: [RFC PATCH 0/3] Adding /dev/rtc device (work in progress)

2024-11-01 Thread Sergey Bugaev
On Fri, Nov 1, 2024 at 1:30 PM Zhaoming Luo  wrote:
> I think it's a good chance to stop
> and gather some suggestions and feedback, so I sent a series of RTC patches.

Hi Zhaoming,

I'm only seeing a single "patch", namely this cover letter. Did you
perhaps accidentally run your git send-email on a single patch file
instead of on the whole series?

Sergey



Re: Using tm_t in a defs file

2024-10-28 Thread Sergey Bugaev
On Mon, Oct 28, 2024 at 9:35 AM Zhaoming Luo  wrote:
> I see, so _IOR is a wrapper of _IOC for calculating an ioctl number.
> This ioctl number is used for invoking the routine in the rtc server. We
> need to define _IOT_rtc_time because calculating RTC_RD_TIME requires
> the ioctl number of rtc, _IOT_rtc_time (like what's mentioned in
> ioctls.h in glibc).

Rather: RTC_RD_TIME *is* the ioctl number. It's a compile-time
constant that's #defined'd to an expression (_IOR(...)) that is
computed (by the C compiler, at compile time) based on the value of
_IOT_rtc_time. This _IOT_rtc_time should be another constant (one that
you need to define), namely the iotcl type-encoding of the 'struct
rtc_time' type — it should encode that the structure is basically just
9 ints, as Samuel said.

User code would just use RTC_RD_TIME as a constant in an ioctl () call
without caring about any particular encoding. The glibc ioctl ()
implementation would look at the RTC_RD_TIME value and understand that
it should send an RPC with a particular ID (matching that of the
pioctl_rtc_rd_time MIG routine exactly) with no data in the request
message, and expect 9 ints in the reply, which it should memcpy out of
the reply message into the user-provided buffer (the third argument to
the ioctl call). To the user code, this is just like an ioctl () call
on e.g. Linux. To the server (and rpctrace etc), it's just a call of
the pioctl_rtc_rd_time MIG routine, and indeed on the server side, you
can and should use the normal MIG mechanisms to handle it.

Do you have a general understanding of how to write the server side of
this -- a simple translator using trivfs? trans/hello.c is a basic
example of that; please feel free to ask me questions if anything
there is unclear. trans/null.c is also fairly simple, and is the
actual implementation of /dev/null and /dev/full.

Sergey



Re: Using tm_t in a defs file

2024-10-27 Thread Sergey Bugaev
On Sun, Oct 27, 2024 at 3:02 PM Zhaoming Luo  wrote:
> I didn't develop it in-tree because I haven't figure out how to write a
> Makefile for an in-tree server. I haven't found a reference or document
> for me to learn writing it. Any recommendations? Maybe I should write
> one based on the Makefile of lwip and add something in the top-level
> Makefile?

There is some brief documentation in the top-level Makeconf (starting
with "Directory makefiles should set"...), and yes, you probably need
to add your directory to prog-subdirs in the top-level Makefile. I'm
not super familiar with the build system myself, but it is somewhat
approachable if you know your way around Make.

> >> /* 9 RTC_RD_TIME */
> >> routine pioctl_rtc_rd_time (
> >>   reqport: io_t;
> >>   inout time: tm_t);
> > Shouldn't this be 'out' rather than 'inout'?
> I think my idea was that time should be a pointer. I think there may be
> two method to correct it now: 1) let time be a pointer (tm_p_t?) 2)
> using 'out' rather than 'inout'.
> Maybe 1) is better? Because the message length will be shorter.

You mention message length, which tells me that you understand that
this is about messaging; good. Let me spell it out anyway: every MIG
routine defines two Mach messages: a request message (from a client to
a server) and a reply message (sent by the server back to the client).
The request message contains 'in' parameter values ('in' being the
implicit default), the reply message contains 'out' parameter values,
and 'inout' parameter values are contained in both.

As for tm_p_t: if you pass an actual pointer (i.e. a memory address)
through MIG, the server will receive just that, a memory address in
the client's address space. Which will be completely useless to it, of
course. You need to actually place the data you want to pass into the
message, by value. In this case the data (rtc_time_t) flows from the
server to the client, so it should be an out parameter in the routine,
so it gets placed in the reply message. Whether the parameter of the
generated C function will be a pointer or not is secondary, getting
the actual thing passed over IPC correctly should be the first
concern.

Next, the type you define for a parameter in MIG does not correspond
100% exactly to the type the generated C function will have; for
example MIG will add a level of indirection (a pointer-to) for an out
or inout parameter; so if you have

routine get_foo(port: mach_port_t; out foo: int);

the C signature will be

kern_return_t get_foo(mach_port_t port, int *foo);

And so for

routine pioctl_rtc_rd_time (
reqport: io_t;
out time: rtc_time_t);

you'd get

kern_return_t pioctl_rtc_rd_time(io_t reqport, rtc_time_t *time);

on the C side, which is what you want. The request message will
contain nothing, and the reply message will contain an rtc_time_t, by
value.

But then: the generated C pioctl_rtc_rd_time () function is not how
glibc will actually invoke your RPC when someone calls ioctl(...,
RTC_RD_TIME, ...). If it was done that way, glibc would have to know,
in advance, all the possible ioctls, and there'd be a giant switch
statement inside ioctl () implementation that would pick the right one
and send the appropriate RPC. That'd be one way to do it, for sure,
but that would not be extensible with out-of-tree ioctls (which is
incidentally what you're trying to do).

So the way this is actually done is clever, if obscure. The message id
of the RPC, along with its signature, is encoded right into the ioctl
number (using the _IOC () macro or one of its wrappers). The ioctl ()
implementation in glibc then picks apart the ioctl number, constructs
the request message according to the signature, sends it off, waits
for a reply from the server, and parses the reply according to the
expected reply signature (also encoded in the ioctl number).

The details are complicated and I won't pretend to fully understand
them myself, luckily you don't have to either; the ioctl ()
implementation exists and works. But the important point is that on
the client side, glibc doesn't use the generated C function to invoke
the routine, and instead does things based on the ioctl number, so
it's crucial that the definition of RTC_RD_TIME constant matches the
signature of the MIG routine.

On Linux, RTC_RD_TIME is defined as _IOR('p', 0x09, struct rtc_time),
and IIUC you plan to keep the same definition. _IOR (..., ..., type)
means an RPC that has a single out-parameter of the given type, so
that's what your MIG routine should be defined as. You'll also have to
define _IOT_rtc_time in a C header (rtc.h) next to the struct rtc_time
definition, using the _IOT macro.

Please tell me if this all makes sense, and if I need to rephrase /
expand on something.

> >> /* 10 RTC_SET_TIME */
> >> routine pioctl_rtc_set_time (
> >>   reqport: io_t;
> >>   time: tm_t);
> > Do I understand it right that this would be more privileged than
> > reading the time?
> Indeed[1]. How to m

Re: Using tm_t in a defs file

2024-10-27 Thread Sergey Bugaev
On Sun, Oct 27, 2024 at 11:46 AM Zhaoming Luo  wrote:
> Hi,

Hi Zhaoming,

> I did the following things in a Debian/Hurd virtual machine.
>
> I was following this link
> 
> to implement a rtc server. My idea is that I should implement a working
> rtc server in user space before adding the source code into the repo
> because I don't want to get stuck in Makefile system before I have a
> working rtc server.

Sure, that makes sense. And it's a great property of the Hurd that you
can in fact develop out-of-tree translators with ease. Though in the
case of rtc, we'd probably want it in-tree eventually.

> I wrote the pioctl.defs (I paste it below), used mig
> to resolve it, and mig told me 'tm_t' is not defined. Then I added the
> following lines in /usr/include/i386-gnu/hurd/ioctl_types.h

If it's MIG itself that complained about a missing type, adding a
definition to a C header won't change anything.

> It still didn't work. How can I use `struct tm` in a user space defs file?

To use tm_t, it would have to be defined in some MIG .defs header (in
a way that matches the C definition). See how timespec_t is defined in
hurd_types.defs for example.

But also, tm_t seems to be a weird type to be used in RPCs. I see that
Linux RTC device ioctls actually operate on a 'struct rtc_time', which
is only similar to a 'struct tm', but not the same thing. I would
presume the RTC actually deals with broken-down tm-like time
representation internally, rather than a timestamp?

If so, it would make sense to me if you defined a type that represents
RTC's time representation right in your .defs file, and used that in
your RPCs. Perhaps like this:

type rtc_time_t = struct {
  int tm_sec;
  ...
};

with a matching definition in C.

> /* TODO: adding other ioctl calls for /dev/rtc in mc146818rtc.h */
> skip; skip; skip; skip; /* 0 1 2 3 */
> skip; skip; skip; skip; /* 4 5 6 7 */
> skip;   /* 8 */
>
> /* 9 RTC_RD_TIME */
> routine pioctl_rtc_rd_time (
>  reqport: io_t;
>  inout time: tm_t);

Shouldn't this be 'out' rather than 'inout'?

> /* 10 RTC_SET_TIME */
> routine pioctl_rtc_set_time (
>  reqport: io_t;
>  time: tm_t);

Do I understand it right that this would be more privileged than
reading the time?

Sergey



Re: More thinking about adding /dev/rtc

2024-10-26 Thread Sergey Bugaev
On Sat, Oct 26, 2024 at 5:45 AM Zhaoming Luo  wrote:
> Hi,

Hi,

> - Which server should have the implementation pioctl-ops.c, pfinet or
> lwip?

/dev/rtc is the Real Time Clock device, right? If so, it has nothing
to do with the TCP/IP stack, in either of the two implementations
(pfinet or lwip).

> The directory of pfinet has the register definitions for rtc
> device[1],

That's simply because pfinet is based on code borrowed from Linux (as
'linux-src/include/linux' in the path suggests). But pfinet is not
meant to provide all the functionality that Linux has, only the TCP/IP
stack.

> but the document mentions that lwip can be a replacement for
> pfinet. Maybe we can move mc146818rtc.h to lwip, or create a new server
> (because pfinet and lwip are for TCP/IP), or there is a server which
> should handle accessing rtc.

Yes, that sounds like it should be a new server whose binary will be
installed at /hurd/rtc. Generally, having more small, isolated
userland servers is a good thing, we're a microkernel system :)

Sergey



Re: [PATCH Hurd]: adding a missing comment

2024-10-25 Thread Sergey Bugaev
On Fri, Oct 25, 2024 at 9:50 AM Samuel Thibault  wrote:
> Zhaoming Luo, le ven. 25 oct. 2024 10:43:29 +0800, a ecrit:
> > it seems a bit unreliable (last commit is 7 months ago).
>
> Last commit not being that recent does not mean it's unreliable: it
> possibly just works and doesn't need updates.

This reminded me of
https://www.theolognion.com/p/npm-now-marks-packages-as-abandoned-after-24h-since-the-last-commit
🙃

(That's satire, of course.)

On Fri, Oct 25, 2024 at 5:49 AM Zhaoming Luo  wrote:
>
> On 11/10/24 12:30 AM, Joshua Branson wrote:
> > Zhaoming, if you have never used git send-email, then I recommend it!
> >
> > This is a short guide that will walk you through how to use it.
> >
> > https://git-send-email.io/
> Thank you Joshua, I have tried it and it is very useful, I didn't
> realized this tool.

It's actually... not most convenient, but mostly easy, once you're
past the stage of setting it up to work with your email provider. I'm
in no way an authority or an expert, but here are my few tips:

To post a one-off patch to this list, you can just do

$ git send-email -1 --to=bug-hurd@gnu.org

Where '-1' means sending the current (latest) commit; you can do more
than 1 of course. You can do multiple --to's, if you want to send the
patch to multiple lists (e.g. both to libc-alpha and bug-hurd, for
glibc patches), as well as --cc to cc specific people. It's a good
idea to cc the people who wrote / last changed the part of code you're
changing.

If you add --rfc, the generated subject line will have [RFC PATCH]
instead of [PATCH], which is roughly analogous to WIP MRs on GitLab or
Draft PRs on GitHub, meaning you want to gather feedback, but don't
expect the patches to merged as-is. If you post a modified version
(aka a re-roll) of your patch (set), add -v2 (or -v3, -v4 etc), which
will result in e.g. [PATCH v2].

When posting a larger patch series, you might want to generate the
patches and send them in two distinct steps. For this, you can use git
format-patch (with pretty much all the same options); that will
generate a bunch of text files in your cwd that you can edit with your
favorite text editor; then you pass the patch files to git send-email
(e.g. 'git send-email *.patch') to actually mail them. It's oftentimes
a good idea to give an overview of a patch series; for this you use
--cover-letter, which will generate a dummy patch number 0, which you
can then write your description over.

> > I personally really like using Emacs' magit mode.  It makes messing
> > around with git things super easy!  Re-order commits, easily reword
> > commit messages, commit a change to an old commit that I made, combine
> > commits, etc.  In my humble opinion, it's one of the easiest ways to
> > work with git.
> >
> I have watched the demo of Magit. It's so attractive but I have used vim
> for three years. I found an alternative for vim which is called vimagit
> but it seems a bit unreliable (last commit is 7 months ago). I think I
> will starting changing to emacs.

Not to discourage you from using Emacs :), but my vim-using friend is
very happy with vim-fugitive, and from what I've seen of his workflow,
it does look/work a lot like Magit. From my personal experience, Magit
is easily one of the best things about Emacs, it might indeed be
superior to command-line Git (which is a very high bar for any Git
UIs, despite all the widely recognized issues with git CLI).

Sergey



Re: Error building Hurd on an existing Hurd

2024-10-21 Thread Sergey Bugaev
On Mon, Oct 21, 2024 at 9:53 PM Samuel Thibault  wrote:
> Ah ok.
>
> Yes :)

Good :)

> He said we was using
>
> https://mail.gnu.org/archive/html/bug-hurd/2023-01/msg00132.html

I admit I didn't follow the link in the original message... Those are
my notes about bootstrapping a toolchain & cross-compiling
Mach/Hurd/glibc from a foreign system, specifically it was Fedora
Linux, so neither a Debian system nor "an existing Hurd".

Zhaoming, if you do follow my cross-compiling/bootstrapping notes, you
should have the latest gnumach sources (including headers). Perhaps
you're accidentally building with the native compiler and not a
cross-compiler, so it looks for headers in /usr/include and not
$PREFIX/include? Perhaps ./configure has figured out that the native
(build) triplet matches the host triplet, and just decided to use
system versions of the various tools? (Does it do that? I have no
idea.)

But yes, if you are on an existing GNU/Hurd system (of a matching
architecture, since we have multiple of those now!), you shouldn't
have to do the whole bootstrapping & cross-compilation dance. Just
install up-to-date versions of gcc/binutils/mig/gnumach-dev from the
system packages (on Debian, something like 'apt build-dep hurd' should
get you all of those, and more), and do a plain './configure && make'
in the Hurd repo, without any of the cross-compilation stuff. Just
like you'd normally build any other project.

Sergey



Re: Error building Hurd on an existing Hurd

2024-10-21 Thread Sergey Bugaev
On Mon, Oct 21, 2024 at 9:38 PM Samuel Thibault  wrote:
> Sergey Bugaev, le lun. 21 oct. 2024 14:47:10 +0300, a ecrit:
> > You must
> > have a fresh enough MIG build (that already generates references to
> > mach_port_name_inlined_t), but older gnumach headers (that don't yet
> > define mach_port_name_inlined_t).
>
> "that don't yet define mach_port_name_inlined_t" ?
>
> Here it is missing the definition. I would on the contrary expect that
> his version of gnumach-dev is too old, missing mach_port_name_inlined_t.

But that's the same thing I said?

Perhaps the word "must" is what's confusing; I meant "you must have"
as in "it looks like you have", not as in "you should have". So: it
looks like Zhaoming has somewhat old Mach headers with a new enough
MIG.

If that is indeed on a Debian GNU/Hurd system and the MIG and the Mach
headers in question are coming from system packages, do you think
maybe this should be considered a bug in the packaging? I'd expect the
version of the mig package that generates mach_port_name_inlined_t
references to depend on the version of gnumach-dev that has the
mach_port_name_inlined_t definition.

Sergey



Re: Error building Hurd on an existing Hurd

2024-10-21 Thread Sergey Bugaev
On Mon, Oct 21, 2024 at 9:21 AM Zhaoming Luo  wrote:
> Hi,

Hi,

> I am trying to build Hurd (76419b67...) from source on an existing Hurd. I 
> found this post. However, when I tried ./configure && make, I got the 
> following error:
>
> default_pagerUser.c: In function 'default_pager_object_create':
> default_pagerUser.c:75:17: error: unknown type name 'mach_port_name_inlined_t'
>75 | mach_port_name_inlined_t memory_object;
>   | ^~~~

The default_pagerUser.c file is generated by MIG.
mach_port_name_inlined_t was added to Mach headers in late 2023 [0],
and then MIG was made to use it in the generated code [1]. You must
have a fresh enough MIG build (that already generates references to
mach_port_name_inlined_t), but older gnumach headers (that don't yet
define mach_port_name_inlined_t).

[0]: 
https://git.savannah.gnu.org/cgit/hurd/gnumach.git/commit/?id=69620634858b2992e1a362e33c95d9a8ee57bce7
[1]: 
https://git.savannah.gnu.org/cgit/hurd/mig.git/commit/?id=3b1fcb2b83bb26d43dc912884499345f561d0b6a

Hope that helps,
Sergey



Re: [web:add translator pages 12/15] add translator/devnode page.

2024-10-16 Thread Sergey Bugaev
On Thu, Oct 17, 2024 at 7:28 AM Amos Jeffries  wrote:
> I would guess that means it provides access to system devices under the
> path "/dev" ?

What it does is it exposes a Mach device as a filesystem node (hence
"devnode"), so you can do open("/dev/foobar") instead of
device_open("foobar"). In particular this means that the Unix
permission model can be used to manage access to the fs node, rather
than you having to have the device master port (= be root).

Sergey



Re: Qoth Q3 2024 & on aarch64-gnu

2024-09-24 Thread Sergey Bugaev
On Tue, Sep 24, 2024 at 4:53 AM  wrote:
> I'm game to try! How would I go about setting up a vm AArch64 image that
>
> runs the Hurd?

It's not much different from building a Hurd image for another
architecture (i686 or x86_64), other than having to use some unmerged
branches.

You should start by getting familiar with bootstrapping a
cross-toolchain and cross-building a Hurd image for i686-gnu, and then
try it with aarch64-gnu. I've previously posted my own little guide at
[0] (but note that you need way more recent binutils/gcc); Flavio's
"cross-hurd" project [1] is also a very useful reference. There's some
info in the wiki [2] too.

[0]: https://mail.gnu.org/archive/html/bug-hurd/2023-01/msg00132.html
[1]: https://github.com/flavioc/cross-hurd
[2]: https://darnassus.sceen.net/~hurd-web/toolchain/cross-gnu/

Also I would be glad to help you with more specific guidance, see below.

> I actually saw this in the irc log that made me ponder that porting
>
> AArch64 is still quite an involved task:
>
>
>  I’ve read the email from solid_black. I remembered how I hoped to help
>
> him with gnumach on arm64 \[16:23\]
>
>
>  Thing is that we made progress, but it felt a bit like finishing the
>
> job would have required a total higher lever of effort, let’s say an
>
> order of magnitude more \[16:24\]

Well, there's a saying that software is never done. Have we "finished"
GNU/Hurd on x86_64? On x86?

Of course Hurd on AArch64 will never have the same number of
features/drivers as say Linux does. But it should be very possible to
get many basic things (serial/console, interrupts/timers, perhaps
GPU/display, flash memory, networking) working for common hardware,
especially if we focus on the hardware that specific boards have. It
could be QEMU's "virt", Raspberry Pi, or whichever boards we the Hurd
community are interested in supporting.

> It would be pretty cool to run Debian GNU/Hurd on the MNT reform or a librem 
> 5.
>
> If we were to fundraise and hire some developers for a "complete" Debian 
> GNU/Hurd AArch64 port,
>
> so that it would run on the MNT reform and/or a librem 5 and/or some other 
> Open
>
> hardware-y AArch64 device that I do not know of...how much would we need to
>
> raise to pay for it? How many developers would we need to hire?

I don't think fundraising for Hurd development is realistic (but what
do I know, I might be wrong).

On the other hand, I imagine if you phrase things the right way, and
e.g. tomorrow Phoronix posts an article titled "GNU/Hurd keeps making
progress in 2024, looks for Rust and ARM driver hackers", some people
might get interested enough to join. Then again, we use plain text
mailing lists and IRC, so even if somebody does get interested, they
will likely get dis-interested before they figure out how to ask the
first question.

> Would it be much cheaper for a complete Debian Hurd AArch64 that one would
>
> run in qemu? It would be cool to start a bbuild box for AArch64.

Yes, QEMU "virt" is a relatively simple and attractive board to
target. And it's not using uncommon/obscure hardware either, it's a
PL011 serial, GIC for interrupts, PSCI for rebooting/suspending,
various virtio devices. Supporting virtio devices would directly
benefit x86 experience, and the other hardware is common/standard in
physical ARM boards too.

> What hardware board currently runs the Hurd?
>
> It would be nice to document the device that runs the Hurd, for those
>
> who want to try to test it and/or help.

azert had something named "Olimex A64 OLinuXino" I believe. But we
only got Mach with a basic userland hello world running on it, not the
Hurd; the Hurd was on QEMu virt.

> If we were to organize a GNU/Hurd hackathon (which would be awesome)

That would be awesome indeed :)

> I would need a lot of help,
>
> setting up a development environment. I would ask lots of questions about
>
> workflows.

Please do! I can't of course speak for others, but I would be glad to
guide you through setting things up. Catch me on IRC, or shoot me an
email, or we could do a call where you try to set things up and I help
you figure it out.

I'm actually liking that as an idea for what to do a call (&
recording) about. What do you think?

> I really don't understand git super well or how to use it.
>
> I have never submitted any code to the Hurd project.

Surely I've seen you post many patches to the wiki? So you already
know a bunch about using Git and submitting patches.

Sergey



[PATCH] hurd: Avoid file_check_access () RPC for access (F_OK)

2024-09-19 Thread Sergey Bugaev
A common use case of access () / faccessat () is checking for file
existence, not any specific access permissions.  In that case, we can
avoid doing the file_check_access () RPC; whether the given path had
been successfully resolved to a file is all we need to know to answer.

This is prompted by GLib switching to use faccessat (F_OK) to implement
g_file_query_exists () for local files.
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4272

Signed-off-by: Sergey Bugaev 
---
 sysdeps/mach/hurd/faccessat.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/sysdeps/mach/hurd/faccessat.c b/sysdeps/mach/hurd/faccessat.c
index 998e31962..6d3d123ab 100644
--- a/sysdeps/mach/hurd/faccessat.c
+++ b/sysdeps/mach/hurd/faccessat.c
@@ -185,6 +185,15 @@ __faccessat_common (int fd, const char *file, int type, 
int at_flags,
return errfunc (err);
 }
 
+  /* If all we wanted was to check for a file existing at the path,
+ then we already got our answer, and we don't need to call
+ file_check_access ().  */
+  if (type == F_OK)
+{
+  __mach_port_deallocate (__mach_task_self (), io);
+  return 0;
+}
+
   /* Find out what types of access we are allowed to this file.  */
   err = __file_check_access (io, &allowed);
   __mach_port_deallocate (__mach_task_self (), io);
-- 
2.46.1




Re: [PATCH gnumach 2/3] add tests for FLOAT/XFLOAT state

2024-08-23 Thread Sergey Bugaev
On Wed, Aug 21, 2024 at 7:37 PM Luca Dariz  wrote:
> +#include 
> +
> +static void printx(struct i386_xfloat_state *state, int size)
> +{
> +  printf("xfloat init %d fp %d exc %d\n",
> + state->initialized, state->fpkind, state->exc_status);
> +  struct i386_xfp_save *xfp = (struct i386_xfp_save *) &state->hw_state[0];
> +  printf("xfp %d %d %d %d %d %d %d %d\n",
> + xfp->fp_control, xfp->fp_status, xfp->fp_tag, xfp->fp_eip,
> + xfp->fp_cs, xfp->fp_opcode, xfp->fp_dp, xfp->fp_ds);

Please make sure to disable this on non-x86. You can disable the whole
test, I guess, or -- would testing something like this also make sense
on other architectures?

Sergey



Re: [PATCH] add xfloat thread state interface

2024-08-05 Thread Sergey Bugaev
On Mon, Aug 5, 2024 at 9:23 PM Samuel Thibault  wrote:
> Luca Dariz, le lun. 05 août 2024 14:52:24 +0200, a ecrit:
> > Il 05/08/24 00:32, Samuel Thibault ha scritto:
> > > Luca Dariz, le ven. 02 août 2024 17:32:34 +0200, a ecrit:
> > > > +#define XFP_STATE_BYTES (sizeof (struct i386_xfp_save))
> > >
> > > That is not sufficient: depending on the sse level and the saving style,
> > > we have various amount of data to store. See fp_xsave_size computed in
> > > init_fpu, we have to save all of that. We thus have to make get_state
> > > check that the user-land buffer is large enough for that. And as I
> > > mentioned on irc, the i386_xfloat_state stucture should contain the
> > > fp_save_kind for glibc to know how to restore it.
> > >
> >
> > Right, maybe we also need a way for userspace to discover the required size?
> > e.g. with a separate call i386_get_xstate_size().
>
> I was thinking that perhaps glibc can compute it itself with cpuid, but
> it'll be simpler to add some call to gnumach indeed.
>
> Samuel

I haven't looked closely, but just a quick reminder that MIG can
return variable-sized data just fine, and the caller (glibc) will then
learn the size after having received the data.

The machine_thread_all_state abstraction (that glibc uses internally)
does make this somewhat awkward though.

Sergey



Re: [PATCH glibc] Add pthread_getname_np and pthread_setname_np for Hurd

2024-07-10 Thread Sergey Bugaev
Hi Flavio,

in general, what's this useful for? Debugging, maybe?

Do you expect the process itself to query its threads' names locally,
or do you expect another process (GDB) to issue thread_get_name
remotely?

On Wed, Jul 10, 2024 at 7:04 PM Flavio Cruz  wrote:
> diff --git a/htl/pt-internal.h b/htl/pt-internal.h
> index 85a7d905..b6ccbe12 100644
> --- a/htl/pt-internal.h
> +++ b/htl/pt-internal.h
> @@ -105,6 +105,10 @@ struct __pthread
>/* Initial sigset for the thread.  */
>sigset_t init_sigset;
>
> +  /* Used to store the thread name through pthread_setname_np.  */
> +  pthread_mutex_t name_lock;

I see other members of struct __pthread are also using
pthread_mutex_t, but is there really a reason why we need that over a
simple libc_lock?

> +  char *thread_name;

Does it make sense to store the name locally? Could pthread_getname_np
call thread_get_name also, if we don't expect it to be a frequent
operation?

Not saying you shouldn't store the name, but let's think of the space
vs performance trade-off and document it.

If you do store it, you should make sure to free it in pt-dealloc.

> +
>/* Thread context.  */
>struct pthread_mcontext mcontext;
>
> diff --git a/sysdeps/htl/pthread.h b/sysdeps/htl/pthread.h
> index fa626ebc..cf42383f 100644
> --- a/sysdeps/htl/pthread.h
> +++ b/sysdeps/htl/pthread.h
> @@ -891,6 +891,17 @@ extern int pthread_setschedparam (pthread_t __thr, int 
> __policy,
>  /* Set thread THREAD's scheduling priority.  */
>  extern int pthread_setschedprio (pthread_t __thr, int __prio) __THROW;
>
> +#ifdef __USE_GNU
> +/* Get thread name visible in the kernel and its interfaces.  */
> +extern int pthread_getname_np (pthread_t __target_thread, char *__buf,
> +  size_t __buflen)
> + __THROW __nonnull ((2));

__attr_access ((__write_only__, 2, 3)) perhaps?

> +
> +/* Set thread name visible in the kernel and its interfaces.  */
> +extern int pthread_setname_np (pthread_t __target_thread, const char *__name)
> + __THROW __nonnull ((2));

Same here, __attr_access ((__read_only__, 2))

> diff --git a/sysdeps/mach/htl/pt-setname-np.c 
> b/sysdeps/mach/htl/pt-setname-np.c
> new file mode 100644
> index ..abc20bf5
> --- /dev/null
> +++ b/sysdeps/mach/htl/pt-setname-np.c
> @@ -0,0 +1,66 @@
> +/* pthread_setname_np.  Mach version.
> +   Copyright (C) 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
> +   .  */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include 
> +#include 

What's hurdlock.h for?

> +
> +int
> +__pthread_setname_np (pthread_t thread, const char *name)
> +{
> +#ifdef HAVE_MACH_THREAD_SET_NAME
> +/* Same as the Mach kernel's thread name size.  */
> +#define THREAD_NAME_SIZE 64
> +  struct __pthread *pthread;
> +  char *oldname, *cp, newname[THREAD_NAME_SIZE];
> +
> +  /* Lookup the thread structure for THREAD.  */
> +  pthread = __pthread_getid (thread);
> +  if (pthread == NULL)
> +return ESRCH;
> +
> +  /* Check for overflow and copy the name into a buffer.  */
> +  if (strlen (name) >= THREAD_NAME_SIZE)
> +return ERANGE;
> +  strncpy (newname, name, THREAD_NAME_SIZE);
> +
> +  oldname = pthread->thread_name;
> +  cp = strdup (newname);
> +  if (cp == NULL)
> +return ENOMEM;
> +
> +  __pthread_mutex_lock (&pthread->name_lock);
> +  oldname = pthread->thread_name;
> +  pthread->thread_name = cp;
> +  __thread_set_name (pthread->kernel_thread, cp);

No checking the return value?

> +  __pthread_mutex_unlock (&pthread->name_lock);
> +
> +  if (oldname != NULL)
> +free (oldname);

Nitpick: no need to check for NULL before freeing.

Sergey



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&m=162142791926428&w=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(), &addr, 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) &state, &state_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;
+   

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(), &addr, 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) &state, &state_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, &state, sizeof(state));
+
+   /*
+*  Make it call fault_handler(subcode, off).
+*/
+   state.ursp = off;
+   state.rip =

[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 published

[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 branchin

[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 a/aarch64/include/ma

[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 oth

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) &&\
-((x

Re: [PATCH] elf-load: Respect PT_GNU_STACK

2024-03-27 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,
-   &stack_base,
-   stack_size,
-   FALSE);
+   (void) vm_map(current_map(), &stack_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, &value, 4))
+   {
+ vm_map_unlock_read (task->map);
+ kmutex_unlock (&hbp->lock);
+ return KERN_INVALID_ADDRESS;
+   }
+
+  equal = (value == lo);
+  if (flags & GSYNC_QUAD)
+   {
+ if (copyin ((const void *) (addr + 4), &value, 4))
+   {
+ vm_map_unlock_read (task->map);
+ kmutex_unlock (&hbp->lock);
+ return KERN_INVALID_ADDRESS;
+   }
+ equal = equal && (value == hi);
+   }
+}
   else
 {
   vm_offset_t paddr = temp_mapping (&va, 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 (&val, (void *) addr, 4))
+{
+  kmutex_unlock (&hbp->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(&request->Head, MACH_RCV_MSG, 0, PAGE_SIZE,
- rcv_port_name, 0, MACH_PORT_NULL);
-  switch (ret)
-{
-case MACH_MSG_SUCCESS:
-  if ((*demuxer)(&request->Head, &reply->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(&last_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(&last_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,
+  

[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, &c, 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 **) &argcptr[1];
@@ -224,6 +230,13 @@ c_start(void **argptr)
   mach_atoi(argv[1], &host_priv_port);
   mach_atoi(argv[2], &device_master_port);
 
+#ifndef PAGE_SIZE
+  vm_statistics_data_t stats;
+  kr = vm_statistics (mach_task_self(), &stats);
+  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(), &local_stack, vm_page_size, TRUE);
+  ASSERT_RET(ret, "can't allocate local stack");
 
   ret = vm_allocate(task, &stack, 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, &thread);
   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)
+

[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

[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]

[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 &t->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 = &t->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].n

[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_wmar

[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_st

[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 (&ss->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 (&ss->critical_section_lock);
-  pending = _hurd_sigstate_pending (ss) & ~ss->blocked;
-  _hurd_sigstate_unlock (ss);
-  if (__glibc_unlikely (!__sigisemptyset (&pending)))
-   /* 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

[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 initially

[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, &count);
 }
 
+#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, &count);
+  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, &count);
+  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) ®s, 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) ®s, ®_size);
+regs.sp = (long) arg_pos;
+regs.pc = (long) startpc;
+thread_set_state (thread, AARCH64_THREAD_STATE,
+ (thread_state_t) ®s, 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




  1   2   3   4   5   6   7   8   9   >