diff mbox series

[v6,3/7] qemu: add support for iOS host

Message ID 20210105022055.12113-4-j@getutm.app
State New
Headers show
Series iOS and Apple Silicon host support | expand

Commit Message

Joelle van Dyne Jan. 5, 2021, 2:20 a.m. UTC
This introduces support for building for iOS hosts. When the correct Xcode
toolchain is used, iOS host will be detected automatically.

* block: disable features not supported by iOS sandbox
* slirp: disable SMB features for iOS
* osdep: disable system() calls for iOS

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 docs/devel/index.rst    |  1 +
 docs/devel/ios.rst      | 28 +++++++++++++++++++++++++++
 configure               | 43 ++++++++++++++++++++++++++++++++++++++++-
 meson.build             |  2 +-
 include/qemu/osdep.h    | 11 +++++++++++
 block.c                 |  2 +-
 block/file-posix.c      | 31 +++++++++++++++++------------
 net/slirp.c             | 16 +++++++--------
 qga/commands-posix.c    |  6 ++++++
 MAINTAINERS             |  7 +++++++
 tests/qtest/meson.build |  7 +++----
 11 files changed, 127 insertions(+), 27 deletions(-)
 create mode 100644 docs/devel/ios.rst

Comments

Philippe Mathieu-Daudé Jan. 12, 2021, 11:56 a.m. UTC | #1
Hi Joelle,

On 1/5/21 3:20 AM, Joelle van Dyne wrote:
> This introduces support for building for iOS hosts. When the correct Xcode
> toolchain is used, iOS host will be detected automatically.
> 
> * block: disable features not supported by iOS sandbox
> * slirp: disable SMB features for iOS
> * osdep: disable system() calls for iOS
> 
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---
>  docs/devel/index.rst    |  1 +
>  docs/devel/ios.rst      | 28 +++++++++++++++++++++++++++
>  configure               | 43 ++++++++++++++++++++++++++++++++++++++++-
>  meson.build             |  2 +-
>  include/qemu/osdep.h    | 11 +++++++++++
>  block.c                 |  2 +-
>  block/file-posix.c      | 31 +++++++++++++++++------------
>  net/slirp.c             | 16 +++++++--------
>  qga/commands-posix.c    |  6 ++++++
>  MAINTAINERS             |  7 +++++++
>  tests/qtest/meson.build |  7 +++----
>  11 files changed, 127 insertions(+), 27 deletions(-)
>  create mode 100644 docs/devel/ios.rst

> 
> diff --git a/docs/devel/index.rst b/docs/devel/index.rst
> index f10ed77e4c..2cc8a13ebe 100644
> --- a/docs/devel/index.rst
> +++ b/docs/devel/index.rst
> @@ -35,3 +35,4 @@ Contents:
>     clocks
>     qom
>     block-coroutine-wrapper
> +   ios
> diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
> new file mode 100644
> index 0000000000..b4ab11bec1
> --- /dev/null
> +++ b/docs/devel/ios.rst
> @@ -0,0 +1,28 @@
> +===========
> +iOS Support
> +===========
> +
> +To run qemu on the iOS platform, some modifications were required. Most of the
> +modifications are conditioned on the ``CONFIG_IOS`` and configuration variable.
> +
> +Build support
> +-------------
> +
> +For the code to compile, certain changes in the block driver and the slirp
> +driver had to be made. There is no ``system()`` call, so it has been replaced
> +with an assertion error. There should be no code path that call system() from
> +iOS.
> +
> +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> +is used instead.

Do you have a CI testing plan for these builds?

Is it possible to add a Gitlab-CI job? If not, on Cirrus-CI?

Thanks,

Phil.
Peter Maydell Jan. 12, 2021, 3:03 p.m. UTC | #2
On Tue, 5 Jan 2021 at 02:25, Joelle van Dyne <j@getutm.app> wrote:
>
> This introduces support for building for iOS hosts. When the correct Xcode
> toolchain is used, iOS host will be detected automatically.
>
> * block: disable features not supported by iOS sandbox
> * slirp: disable SMB features for iOS
> * osdep: disable system() calls for iOS
>
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---
>  docs/devel/index.rst    |  1 +
>  docs/devel/ios.rst      | 28 +++++++++++++++++++++++++++
>  configure               | 43 ++++++++++++++++++++++++++++++++++++++++-
>  meson.build             |  2 +-
>  include/qemu/osdep.h    | 11 +++++++++++
>  block.c                 |  2 +-
>  block/file-posix.c      | 31 +++++++++++++++++------------
>  net/slirp.c             | 16 +++++++--------
>  qga/commands-posix.c    |  6 ++++++
>  MAINTAINERS             |  7 +++++++
>  tests/qtest/meson.build |  7 +++----
>  11 files changed, 127 insertions(+), 27 deletions(-)
>  create mode 100644 docs/devel/ios.rst
>
> diff --git a/docs/devel/index.rst b/docs/devel/index.rst
> index f10ed77e4c..2cc8a13ebe 100644
> --- a/docs/devel/index.rst
> +++ b/docs/devel/index.rst
> @@ -35,3 +35,4 @@ Contents:
>     clocks
>     qom
>     block-coroutine-wrapper
> +   ios
> diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
> new file mode 100644
> index 0000000000..b4ab11bec1
> --- /dev/null
> +++ b/docs/devel/ios.rst
> @@ -0,0 +1,28 @@
> +===========
> +iOS Support
> +===========
> +
> +To run qemu on the iOS platform, some modifications were required. Most of the

QEMU is upper-cased.

> +modifications are conditioned on the ``CONFIG_IOS`` and configuration variable.
> +
> +Build support
> +-------------
> +
> +For the code to compile, certain changes in the block driver and the slirp
> +driver had to be made. There is no ``system()`` call, so it has been replaced
> +with an assertion error. There should be no code path that call system() from

"calls"

> +iOS.
> +
> +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> +is used instead.
> +
> +JIT support
> +-----------
> +
> +On iOS, allocating RWX pages require special entitlements not usually granted to

"requires"

> +apps. However, it is possible to use `bulletproof JIT`_ with a development
> +certificate. This means that we need to allocate one chunk of memory with RX
> +permissions and then mirror map the same memory with RW permissions. We generate
> +code to the mirror mapping and execute the original mapping.
> +
> +.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
> diff --git a/configure b/configure
> index 744d1990be..c1a08f0171 100755
> --- a/configure
> +++ b/configure
> @@ -560,6 +560,19 @@ EOF
>    compile_object
>  }
>
> +check_ios() {
> +  cat > $TMPC <<EOF
> +#ifdef __APPLE__
> +#import "TargetConditionals.h"
> +#if !TARGET_OS_IPHONE
> +#error TARGET_OS_IPHONE not true
> +#endif
> +#endif
> +int main(void) { return 0; }
> +EOF
> +  compile_object
> +}
> +
>  check_include() {
>  cat > $TMPC <<EOF
>  #include <$1>
> @@ -602,7 +615,11 @@ elif check_define __DragonFly__ ; then
>  elif check_define __NetBSD__; then
>    targetos='NetBSD'
>  elif check_define __APPLE__; then
> -  targetos='Darwin'
> +  if check_ios ; then
> +    targetos='iOS'
> +  else
> +    targetos='Darwin'
> +  fi
>  else
>    # This is a fatal error, but don't report it yet, because we
>    # might be going to just print the --help text, or it might

So here targetos=iOS and targetos=Darwin are separate things...

> @@ -6974,6 +7012,9 @@ if test "$cross_compile" = "yes"; then
>      if test "$linux" = "yes" ; then
>          echo "system = 'linux'" >> $cross
>      fi
> +    if test "$darwin" = "yes" ; then
> +        echo "system = 'darwin'" >> $cross
> +    fi

...so why is this needed if we're not "darwin", but "iOS"...

>      case "$ARCH" in
>          i386|x86_64)
>              echo "cpu_family = 'x86'" >> $cross
> diff --git a/meson.build b/meson.build
> index 9a640d3407..ee333b7a94 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -181,7 +181,7 @@ if targetos == 'windows'
>                                        include_directories: include_directories('.'))
>  elif targetos == 'darwin'
>    coref = dependency('appleframeworks', modules: 'CoreFoundation')
> -  iokit = dependency('appleframeworks', modules: 'IOKit')
> +  iokit = dependency('appleframeworks', modules: 'IOKit', required: 'CONFIG_IOS' not in config_host)
>    cocoa = dependency('appleframeworks', modules: 'Cocoa', required: get_option('cocoa'))
>  elif targetos == 'sunos'
>    socket = [cc.find_library('socket'),

...and here ios seems to be a subtype of darwin, not a different
kind of targetos. That's a bit confusing. Maybe this is Meson's fault ?

> diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
> index f9ec8c84e9..eb8d06cbf5 100644
> --- a/include/qemu/osdep.h
> +++ b/include/qemu/osdep.h
> @@ -686,4 +686,15 @@ char *qemu_get_host_name(Error **errp);
>   */
>  size_t qemu_get_host_physmem(void);
>
> +/**
> + * iOS does not support system() so we replace it with an assertion failure.
> + */
> +#ifdef CONFIG_IOS
> +#define system ios_does_not_support_system
> +static inline int ios_does_not_support_system(const char *command)
> +{
> +    assert(0);
> +}
> +#endif /* CONFIG_IOS */
> +
>  #endif
> diff --git a/block.c b/block.c
> index 8f177504d4..984a73a82c 100644
> --- a/block.c
> +++ b/block.c
> @@ -54,7 +54,7 @@
>  #ifdef CONFIG_BSD
>  #include <sys/ioctl.h>
>  #include <sys/queue.h>
> -#ifndef __DragonFly__
> +#if !defined(__DragonFly__) && !defined(CONFIG_IOS)
>  #include <sys/disk.h>
>  #endif

Instead of extending this ifdef of OSes, can we add a meson.build
test for "does sys/disk.h exist" and then use #ifdef HAVE_SYS_DISK_H ?
(HAVE_PTY_H is probably a good example to crib from.)

This is part of a general preference we have for not testing
"are we building for host OS Foo" if we can test the specific
property we care about instead.

>  #endif
> diff --git a/block/file-posix.c b/block/file-posix.c
> index c34bb9fac1..9f556322e6 100644
> --- a/block/file-posix.c
> +++ b/block/file-posix.c
> @@ -181,7 +181,17 @@ typedef struct BDRVRawReopenState {
>      bool check_cache_dropped;
>  } BDRVRawReopenState;
>
> -static int fd_open(BlockDriverState *bs);
> +static int fd_open(BlockDriverState *bs)
> +{
> +    BDRVRawState *s = bs->opaque;
> +
> +    /* this is just to ensure s->fd is sane (its called by io ops) */
> +    if (s->fd >= 0) {
> +        return 0;
> +    }
> +    return -EIO;
> +}
> +
>  static int64_t raw_getlength(BlockDriverState *bs);
>
>  typedef struct RawPosixAIOData {
> @@ -252,6 +262,12 @@ static int raw_normalize_devicepath(const char **filename, Error **errp)
>  }
>  #endif
>
> +#if defined(CONFIG_IOS)
> +static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
> +{
> +    return -ENOTSUP; /* not supported on iOS */
> +}
> +#else /* CONFIG_IOS */
>  /*
>   * Get logical block size via ioctl. On success store it in @sector_size_p.
>   */
> @@ -284,6 +300,7 @@ static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
>
>      return success ? 0 : -errno;
>  }
> +#endif /* !CONFIG_IOS */
>
>  /**
>   * Get physical block size of @fd.
> @@ -2307,7 +2324,7 @@ again:
>          }
>          if (size == 0)
>  #endif
> -#if defined(__APPLE__) && defined(__MACH__)
> +#if !defined(CONFIG_IOS) && defined(__APPLE__) && defined(__MACH__)
>          {
>              uint64_t sectors = 0;
>              uint32_t sector_size = 0;
> @@ -3543,16 +3560,6 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
>  }
>  #endif /* linux */
>
> -static int fd_open(BlockDriverState *bs)
> -{
> -    BDRVRawState *s = bs->opaque;
> -
> -    /* this is just to ensure s->fd is sane (its called by io ops) */
> -    if (s->fd >= 0)
> -        return 0;
> -    return -EIO;
> -}
> -
>  static coroutine_fn int
>  hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
>  {
> diff --git a/net/slirp.c b/net/slirp.c
> index 77042e6df7..8413042c09 100644
> --- a/net/slirp.c
> +++ b/net/slirp.c
> @@ -27,7 +27,7 @@
>  #include "net/slirp.h"
>
>
> -#ifndef _WIN32
> +#if !defined(_WIN32) && !defined(CONFIG_IOS)
>  #include <pwd.h>
>  #include <sys/wait.h>
>  #endif
> @@ -90,7 +90,7 @@ typedef struct SlirpState {
>      Slirp *slirp;
>      Notifier poll_notifier;
>      Notifier exit_notifier;
> -#ifndef _WIN32
> +#if !defined(_WIN32) && !defined(CONFIG_IOS)
>      gchar *smb_dir;
>  #endif
>      GSList *fwd;

This sort of ifdeffery should probably also be changed to test
what it really cares about rather than just adding another host OS
type to the list.

> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> index c089e38120..81e40ac14a 100644
> --- a/qga/commands-posix.c
> +++ b/qga/commands-posix.c

Does it even make sense to build the guest agent for iOS ?
It's not like you can run iOS inside QEMU...

> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 6a67c538be..42b46a7ca4 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -46,12 +46,11 @@ qtests_i386 = \
>    (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-test'] : []) +              \
>    (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-swtpm-test'] : []) +        \
>    (config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) +              \
> +  (not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test', 'hd-geo-test'] : []) +      \
>    qtests_pci +                                                                              \
>    ['fdc-test',
>     'ide-test',
> -   'hd-geo-test',
>     'boot-order-test',
> -   'bios-tables-test',
>     'rtc-test',
>     'i440fx-test',
>     'fuzz-test',
> @@ -148,9 +147,9 @@ qtests_arm = \
>     'boot-serial-test',
>     'hexloader-test']
>
> -# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional
> +# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional (except on iOS)

So, why is bios-tables-test not something to run if we're building for iOS?
If there's a good reason for the exclusion the comment should say what it is.

>  qtests_aarch64 = \
> -  (cpu != 'arm' ? ['bios-tables-test'] : []) +                                                  \
> +  (cpu != 'arm' and not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test'] : []) +        \
>    (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) +        \
>    (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) +  \
>    ['arm-cpu-features',
> --
> 2.28.0

thanks
-- PMM
Joelle van Dyne Jan. 12, 2021, 10:18 p.m. UTC | #3
I think this was discussed before but the main issue right now is that
there's no packaging system (like homebrew) for iOS cross building on
Mac. Stefan suggested caching built libraries in an external location
to use with the CI. I think this can be done but would require some
thought to it. I am open to other ideas as well (like pretending to
build for iOS while actually building for macOS).

-j

On Tue, Jan 12, 2021 at 3:56 AM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Hi Joelle,
>
> On 1/5/21 3:20 AM, Joelle van Dyne wrote:
> > This introduces support for building for iOS hosts. When the correct Xcode
> > toolchain is used, iOS host will be detected automatically.
> >
> > * block: disable features not supported by iOS sandbox
> > * slirp: disable SMB features for iOS
> > * osdep: disable system() calls for iOS
> >
> > Signed-off-by: Joelle van Dyne <j@getutm.app>
> > ---
> >  docs/devel/index.rst    |  1 +
> >  docs/devel/ios.rst      | 28 +++++++++++++++++++++++++++
> >  configure               | 43 ++++++++++++++++++++++++++++++++++++++++-
> >  meson.build             |  2 +-
> >  include/qemu/osdep.h    | 11 +++++++++++
> >  block.c                 |  2 +-
> >  block/file-posix.c      | 31 +++++++++++++++++------------
> >  net/slirp.c             | 16 +++++++--------
> >  qga/commands-posix.c    |  6 ++++++
> >  MAINTAINERS             |  7 +++++++
> >  tests/qtest/meson.build |  7 +++----
> >  11 files changed, 127 insertions(+), 27 deletions(-)
> >  create mode 100644 docs/devel/ios.rst
>
> >
> > diff --git a/docs/devel/index.rst b/docs/devel/index.rst
> > index f10ed77e4c..2cc8a13ebe 100644
> > --- a/docs/devel/index.rst
> > +++ b/docs/devel/index.rst
> > @@ -35,3 +35,4 @@ Contents:
> >     clocks
> >     qom
> >     block-coroutine-wrapper
> > +   ios
> > diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
> > new file mode 100644
> > index 0000000000..b4ab11bec1
> > --- /dev/null
> > +++ b/docs/devel/ios.rst
> > @@ -0,0 +1,28 @@
> > +===========
> > +iOS Support
> > +===========
> > +
> > +To run qemu on the iOS platform, some modifications were required. Most of the
> > +modifications are conditioned on the ``CONFIG_IOS`` and configuration variable.
> > +
> > +Build support
> > +-------------
> > +
> > +For the code to compile, certain changes in the block driver and the slirp
> > +driver had to be made. There is no ``system()`` call, so it has been replaced
> > +with an assertion error. There should be no code path that call system() from
> > +iOS.
> > +
> > +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> > +is used instead.
>
> Do you have a CI testing plan for these builds?
>
> Is it possible to add a Gitlab-CI job? If not, on Cirrus-CI?
>
> Thanks,
>
> Phil.
>
>
Joelle van Dyne Jan. 12, 2021, 10:37 p.m. UTC | #4
On Tue, Jan 12, 2021 at 7:03 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 5 Jan 2021 at 02:25, Joelle van Dyne <j@getutm.app> wrote:
> >
> > This introduces support for building for iOS hosts. When the correct Xcode
> > toolchain is used, iOS host will be detected automatically.
> >
> > * block: disable features not supported by iOS sandbox
> > * slirp: disable SMB features for iOS
> > * osdep: disable system() calls for iOS
> >
> > Signed-off-by: Joelle van Dyne <j@getutm.app>
> > ---
> >  docs/devel/index.rst    |  1 +
> >  docs/devel/ios.rst      | 28 +++++++++++++++++++++++++++
> >  configure               | 43 ++++++++++++++++++++++++++++++++++++++++-
> >  meson.build             |  2 +-
> >  include/qemu/osdep.h    | 11 +++++++++++
> >  block.c                 |  2 +-
> >  block/file-posix.c      | 31 +++++++++++++++++------------
> >  net/slirp.c             | 16 +++++++--------
> >  qga/commands-posix.c    |  6 ++++++
> >  MAINTAINERS             |  7 +++++++
> >  tests/qtest/meson.build |  7 +++----
> >  11 files changed, 127 insertions(+), 27 deletions(-)
> >  create mode 100644 docs/devel/ios.rst
> >
> > diff --git a/docs/devel/index.rst b/docs/devel/index.rst
> > index f10ed77e4c..2cc8a13ebe 100644
> > --- a/docs/devel/index.rst
> > +++ b/docs/devel/index.rst
> > @@ -35,3 +35,4 @@ Contents:
> >     clocks
> >     qom
> >     block-coroutine-wrapper
> > +   ios
> > diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
> > new file mode 100644
> > index 0000000000..b4ab11bec1
> > --- /dev/null
> > +++ b/docs/devel/ios.rst
> > @@ -0,0 +1,28 @@
> > +===========
> > +iOS Support
> > +===========
> > +
> > +To run qemu on the iOS platform, some modifications were required. Most of the
>
> QEMU is upper-cased.
>
> > +modifications are conditioned on the ``CONFIG_IOS`` and configuration variable.
> > +
> > +Build support
> > +-------------
> > +
> > +For the code to compile, certain changes in the block driver and the slirp
> > +driver had to be made. There is no ``system()`` call, so it has been replaced
> > +with an assertion error. There should be no code path that call system() from
>
> "calls"
>
> > +iOS.
> > +
> > +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> > +is used instead.
> > +
> > +JIT support
> > +-----------
> > +
> > +On iOS, allocating RWX pages require special entitlements not usually granted to
>
> "requires"
>
> > +apps. However, it is possible to use `bulletproof JIT`_ with a development
> > +certificate. This means that we need to allocate one chunk of memory with RX
> > +permissions and then mirror map the same memory with RW permissions. We generate
> > +code to the mirror mapping and execute the original mapping.
> > +
> > +.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
> > diff --git a/configure b/configure
> > index 744d1990be..c1a08f0171 100755
> > --- a/configure
> > +++ b/configure
> > @@ -560,6 +560,19 @@ EOF
> >    compile_object
> >  }
> >
> > +check_ios() {
> > +  cat > $TMPC <<EOF
> > +#ifdef __APPLE__
> > +#import "TargetConditionals.h"
> > +#if !TARGET_OS_IPHONE
> > +#error TARGET_OS_IPHONE not true
> > +#endif
> > +#endif
> > +int main(void) { return 0; }
> > +EOF
> > +  compile_object
> > +}
> > +
> >  check_include() {
> >  cat > $TMPC <<EOF
> >  #include <$1>
> > @@ -602,7 +615,11 @@ elif check_define __DragonFly__ ; then
> >  elif check_define __NetBSD__; then
> >    targetos='NetBSD'
> >  elif check_define __APPLE__; then
> > -  targetos='Darwin'
> > +  if check_ios ; then
> > +    targetos='iOS'
> > +  else
> > +    targetos='Darwin'
> > +  fi
> >  else
> >    # This is a fatal error, but don't report it yet, because we
> >    # might be going to just print the --help text, or it might
>
> So here targetos=iOS and targetos=Darwin are separate things...
>
> > @@ -6974,6 +7012,9 @@ if test "$cross_compile" = "yes"; then
> >      if test "$linux" = "yes" ; then
> >          echo "system = 'linux'" >> $cross
> >      fi
> > +    if test "$darwin" = "yes" ; then
> > +        echo "system = 'darwin'" >> $cross
> > +    fi
>
> ...so why is this needed if we're not "darwin", but "iOS"...
iOS and macOS being treated the same works in 99% of the cases which
is why this patch is relatively small. For the 1% of time the two
systems behave differently, I added CONFIG_IOS. It's a bit of a hack,
but the alternative is to include <TargetConditionals.h> and check for
"TARGET_OS_IPHONE" (which is how it's usually done).

>
> >      case "$ARCH" in
> >          i386|x86_64)
> >              echo "cpu_family = 'x86'" >> $cross
> > diff --git a/meson.build b/meson.build
> > index 9a640d3407..ee333b7a94 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -181,7 +181,7 @@ if targetos == 'windows'
> >                                        include_directories: include_directories('.'))
> >  elif targetos == 'darwin'
> >    coref = dependency('appleframeworks', modules: 'CoreFoundation')
> > -  iokit = dependency('appleframeworks', modules: 'IOKit')
> > +  iokit = dependency('appleframeworks', modules: 'IOKit', required: 'CONFIG_IOS' not in config_host)
> >    cocoa = dependency('appleframeworks', modules: 'Cocoa', required: get_option('cocoa'))
> >  elif targetos == 'sunos'
> >    socket = [cc.find_library('socket'),
>
> ...and here ios seems to be a subtype of darwin, not a different
> kind of targetos. That's a bit confusing. Maybe this is Meson's fault ?
Meson recognizes 'darwin' only for both macOS and iOS.

>
> > diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
> > index f9ec8c84e9..eb8d06cbf5 100644
> > --- a/include/qemu/osdep.h
> > +++ b/include/qemu/osdep.h
> > @@ -686,4 +686,15 @@ char *qemu_get_host_name(Error **errp);
> >   */
> >  size_t qemu_get_host_physmem(void);
> >
> > +/**
> > + * iOS does not support system() so we replace it with an assertion failure.
> > + */
> > +#ifdef CONFIG_IOS
> > +#define system ios_does_not_support_system
> > +static inline int ios_does_not_support_system(const char *command)
> > +{
> > +    assert(0);
> > +}
> > +#endif /* CONFIG_IOS */
> > +
> >  #endif
> > diff --git a/block.c b/block.c
> > index 8f177504d4..984a73a82c 100644
> > --- a/block.c
> > +++ b/block.c
> > @@ -54,7 +54,7 @@
> >  #ifdef CONFIG_BSD
> >  #include <sys/ioctl.h>
> >  #include <sys/queue.h>
> > -#ifndef __DragonFly__
> > +#if !defined(__DragonFly__) && !defined(CONFIG_IOS)
> >  #include <sys/disk.h>
> >  #endif
>
> Instead of extending this ifdef of OSes, can we add a meson.build
> test for "does sys/disk.h exist" and then use #ifdef HAVE_SYS_DISK_H ?
> (HAVE_PTY_H is probably a good example to crib from.)
Can be done.

>
> This is part of a general preference we have for not testing
> "are we building for host OS Foo" if we can test the specific
> property we care about instead.
>
> >  #endif
> > diff --git a/block/file-posix.c b/block/file-posix.c
> > index c34bb9fac1..9f556322e6 100644
> > --- a/block/file-posix.c
> > +++ b/block/file-posix.c
> > @@ -181,7 +181,17 @@ typedef struct BDRVRawReopenState {
> >      bool check_cache_dropped;
> >  } BDRVRawReopenState;
> >
> > -static int fd_open(BlockDriverState *bs);
> > +static int fd_open(BlockDriverState *bs)
> > +{
> > +    BDRVRawState *s = bs->opaque;
> > +
> > +    /* this is just to ensure s->fd is sane (its called by io ops) */
> > +    if (s->fd >= 0) {
> > +        return 0;
> > +    }
> > +    return -EIO;
> > +}
> > +
> >  static int64_t raw_getlength(BlockDriverState *bs);
> >
> >  typedef struct RawPosixAIOData {
> > @@ -252,6 +262,12 @@ static int raw_normalize_devicepath(const char **filename, Error **errp)
> >  }
> >  #endif
> >
> > +#if defined(CONFIG_IOS)
> > +static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
> > +{
> > +    return -ENOTSUP; /* not supported on iOS */
> > +}
> > +#else /* CONFIG_IOS */
> >  /*
> >   * Get logical block size via ioctl. On success store it in @sector_size_p.
> >   */
> > @@ -284,6 +300,7 @@ static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
> >
> >      return success ? 0 : -errno;
> >  }
> > +#endif /* !CONFIG_IOS */
> >
> >  /**
> >   * Get physical block size of @fd.
> > @@ -2307,7 +2324,7 @@ again:
> >          }
> >          if (size == 0)
> >  #endif
> > -#if defined(__APPLE__) && defined(__MACH__)
> > +#if !defined(CONFIG_IOS) && defined(__APPLE__) && defined(__MACH__)
> >          {
> >              uint64_t sectors = 0;
> >              uint32_t sector_size = 0;
> > @@ -3543,16 +3560,6 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
> >  }
> >  #endif /* linux */
> >
> > -static int fd_open(BlockDriverState *bs)
> > -{
> > -    BDRVRawState *s = bs->opaque;
> > -
> > -    /* this is just to ensure s->fd is sane (its called by io ops) */
> > -    if (s->fd >= 0)
> > -        return 0;
> > -    return -EIO;
> > -}
> > -
> >  static coroutine_fn int
> >  hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
> >  {
> > diff --git a/net/slirp.c b/net/slirp.c
> > index 77042e6df7..8413042c09 100644
> > --- a/net/slirp.c
> > +++ b/net/slirp.c
> > @@ -27,7 +27,7 @@
> >  #include "net/slirp.h"
> >
> >
> > -#ifndef _WIN32
> > +#if !defined(_WIN32) && !defined(CONFIG_IOS)
> >  #include <pwd.h>
> >  #include <sys/wait.h>
> >  #endif
> > @@ -90,7 +90,7 @@ typedef struct SlirpState {
> >      Slirp *slirp;
> >      Notifier poll_notifier;
> >      Notifier exit_notifier;
> > -#ifndef _WIN32
> > +#if !defined(_WIN32) && !defined(CONFIG_IOS)
> >      gchar *smb_dir;
> >  #endif
> >      GSList *fwd;
>
> This sort of ifdeffery should probably also be changed to test
> what it really cares about rather than just adding another host OS
> type to the list.
I can refactor to test for SMB support and replace the host OS checks.

>
> > diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> > index c089e38120..81e40ac14a 100644
> > --- a/qga/commands-posix.c
> > +++ b/qga/commands-posix.c
>
> Does it even make sense to build the guest agent for iOS ?
> It's not like you can run iOS inside QEMU...
Not currently no, but do we preclude the option?

>
> > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> > index 6a67c538be..42b46a7ca4 100644
> > --- a/tests/qtest/meson.build
> > +++ b/tests/qtest/meson.build
> > @@ -46,12 +46,11 @@ qtests_i386 = \
> >    (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-test'] : []) +              \
> >    (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-swtpm-test'] : []) +        \
> >    (config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) +              \
> > +  (not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test', 'hd-geo-test'] : []) +      \
> >    qtests_pci +                                                                              \
> >    ['fdc-test',
> >     'ide-test',
> > -   'hd-geo-test',
> >     'boot-order-test',
> > -   'bios-tables-test',
> >     'rtc-test',
> >     'i440fx-test',
> >     'fuzz-test',
> > @@ -148,9 +147,9 @@ qtests_arm = \
> >     'boot-serial-test',
> >     'hexloader-test']
> >
> > -# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional
> > +# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional (except on iOS)
>
> So, why is bios-tables-test not something to run if we're building for iOS?
> If there's a good reason for the exclusion the comment should say what it is.
Actually this was left over from a previous version of the patch where
I excluded all tests that use system(). Now calling system() will just
fail the test so there's no reason to exclude these anymore.

-j

>
> >  qtests_aarch64 = \
> > -  (cpu != 'arm' ? ['bios-tables-test'] : []) +                                                  \
> > +  (cpu != 'arm' and not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test'] : []) +        \
> >    (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) +        \
> >    (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) +  \
> >    ['arm-cpu-features',
> > --
> > 2.28.0
>
> thanks
> -- PMM
Peter Maydell Jan. 21, 2021, 6:53 p.m. UTC | #5
On Tue, 5 Jan 2021 at 02:25, Joelle van Dyne <j@getutm.app> wrote:
>
> This introduces support for building for iOS hosts. When the correct Xcode
> toolchain is used, iOS host will be detected automatically.
>
> * block: disable features not supported by iOS sandbox
> * slirp: disable SMB features for iOS
> * osdep: disable system() calls for iOS

> +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> +is used instead.

Just a note since it came up in another thread today, but
looking at libucontext its aarch64 backend doesn't handle
the floating point registers. I think if the *context
routines don't save/restore the callee-saves fp regs
(v8-v15, FPCR) then it's liable to result in tricky-to-track
down bugs where some kept-in-a-callee-saves-fp-register data
from a function further up the callstack gets corrupted, depending
on what the compiler happens to do. It would be good to work with
the libucontext maintainers to add that functionality.

thanks
-- PMM
Philippe Mathieu-Daudé Nov. 28, 2023, 3:12 p.m. UTC | #6
(Cc'ing Ariadne, libucontext maintainer)

On 21/1/21 19:53, Peter Maydell wrote:
> On Tue, 5 Jan 2021 at 02:25, Joelle van Dyne <j@getutm.app> wrote:
>>
>> This introduces support for building for iOS hosts. When the correct Xcode
>> toolchain is used, iOS host will be detected automatically.
>>
>> * block: disable features not supported by iOS sandbox
>> * slirp: disable SMB features for iOS
>> * osdep: disable system() calls for iOS
> 
>> +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
>> +is used instead.
> 
> Just a note since it came up in another thread today, but
> looking at libucontext its aarch64 backend doesn't handle
> the floating point registers. I think if the *context
> routines don't save/restore the callee-saves fp regs
> (v8-v15, FPCR) then it's liable to result in tricky-to-track
> down bugs where some kept-in-a-callee-saves-fp-register data
> from a function further up the callstack gets corrupted, depending
> on what the compiler happens to do. It would be good to work with
> the libucontext maintainers to add that functionality.

Per https://github.com/kaniini/libucontext/blob/master/README.md#caveats
this is a design choice:

   Only basic GPR registers are saved and restored when context swapping.
   The glibc implementation uses hardware capability detection to
   save/restore other register groups, such as the FPU registers or
   vector processing (AltiVec/AVX/NEON) registers. Adding this capability
   detection would significantly increase the complexity of the project
   and thus is not implemented. Support for compiling in code to
   save/restore FPU registers or vector registers may be added in a later
   release as a build-time setting -- for now, we assume a soft-float ABI
   with no optional processor features.

Minor update in 2022:
https://github.com/kaniini/libucontext/commit/5244775fb93ab9

   This is a work in progress, as newer compilers will spill even
   non-floating-point state through floating point registers when allowed
   to do so.

Regards,

Phil.
diff mbox series

Patch

diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index f10ed77e4c..2cc8a13ebe 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -35,3 +35,4 @@  Contents:
    clocks
    qom
    block-coroutine-wrapper
+   ios
diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
new file mode 100644
index 0000000000..b4ab11bec1
--- /dev/null
+++ b/docs/devel/ios.rst
@@ -0,0 +1,28 @@ 
+===========
+iOS Support
+===========
+
+To run qemu on the iOS platform, some modifications were required. Most of the
+modifications are conditioned on the ``CONFIG_IOS`` and configuration variable.
+
+Build support
+-------------
+
+For the code to compile, certain changes in the block driver and the slirp
+driver had to be made. There is no ``system()`` call, so it has been replaced
+with an assertion error. There should be no code path that call system() from
+iOS.
+
+``ucontext`` support is broken on iOS. The implementation from ``libucontext``
+is used instead.
+
+JIT support
+-----------
+
+On iOS, allocating RWX pages require special entitlements not usually granted to
+apps. However, it is possible to use `bulletproof JIT`_ with a development
+certificate. This means that we need to allocate one chunk of memory with RX
+permissions and then mirror map the same memory with RW permissions. We generate
+code to the mirror mapping and execute the original mapping.
+
+.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
diff --git a/configure b/configure
index 744d1990be..c1a08f0171 100755
--- a/configure
+++ b/configure
@@ -560,6 +560,19 @@  EOF
   compile_object
 }
 
+check_ios() {
+  cat > $TMPC <<EOF
+#ifdef __APPLE__
+#import "TargetConditionals.h"
+#if !TARGET_OS_IPHONE
+#error TARGET_OS_IPHONE not true
+#endif
+#endif
+int main(void) { return 0; }
+EOF
+  compile_object
+}
+
 check_include() {
 cat > $TMPC <<EOF
 #include <$1>
@@ -602,7 +615,11 @@  elif check_define __DragonFly__ ; then
 elif check_define __NetBSD__; then
   targetos='NetBSD'
 elif check_define __APPLE__; then
-  targetos='Darwin'
+  if check_ios ; then
+    targetos='iOS'
+  else
+    targetos='Darwin'
+  fi
 else
   # This is a fatal error, but don't report it yet, because we
   # might be going to just print the --help text, or it might
@@ -779,6 +796,22 @@  Darwin)
   # won't work when we're compiling with gcc as a C compiler.
   QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
 ;;
+iOS)
+  bsd="yes"
+  darwin="yes"
+  ios="yes"
+  if [ "$cpu" = "x86_64" ] ; then
+    QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
+    QEMU_LDFLAGS="-arch x86_64 $QEMU_LDFLAGS"
+  fi
+  host_block_device_support="no"
+  audio_drv_list=""
+  audio_possible_drivers=""
+  QEMU_LDFLAGS="-framework CoreFoundation $QEMU_LDFLAGS"
+  # Disable attempts to use ObjectiveC features in os/object.h since they
+  # won't work when we're compiling with gcc as a C compiler.
+  QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
+;;
 SunOS)
   solaris="yes"
   make="${MAKE-gmake}"
@@ -5992,6 +6025,10 @@  if test "$darwin" = "yes" ; then
   echo "CONFIG_DARWIN=y" >> $config_host_mak
 fi
 
+if test "$ios" = "yes" ; then
+  echo "CONFIG_IOS=y" >> $config_host_mak
+fi
+
 if test "$solaris" = "yes" ; then
   echo "CONFIG_SOLARIS=y" >> $config_host_mak
 fi
@@ -6956,6 +6993,7 @@  echo "cpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
 echo "[binaries]" >> $cross
 echo "c = [$(meson_quote $cc)]" >> $cross
 test -n "$cxx" && echo "cpp = [$(meson_quote $cxx)]" >> $cross
+test -n "$objcc" && echo "objc = [$(meson_quote $objcc)]" >> $cross
 echo "ar = [$(meson_quote $ar)]" >> $cross
 echo "nm = [$(meson_quote $nm)]" >> $cross
 echo "pkgconfig = [$(meson_quote $pkg_config_exe)]" >> $cross
@@ -6974,6 +7012,9 @@  if test "$cross_compile" = "yes"; then
     if test "$linux" = "yes" ; then
         echo "system = 'linux'" >> $cross
     fi
+    if test "$darwin" = "yes" ; then
+        echo "system = 'darwin'" >> $cross
+    fi
     case "$ARCH" in
         i386|x86_64)
             echo "cpu_family = 'x86'" >> $cross
diff --git a/meson.build b/meson.build
index 9a640d3407..ee333b7a94 100644
--- a/meson.build
+++ b/meson.build
@@ -181,7 +181,7 @@  if targetos == 'windows'
                                       include_directories: include_directories('.'))
 elif targetos == 'darwin'
   coref = dependency('appleframeworks', modules: 'CoreFoundation')
-  iokit = dependency('appleframeworks', modules: 'IOKit')
+  iokit = dependency('appleframeworks', modules: 'IOKit', required: 'CONFIG_IOS' not in config_host)
   cocoa = dependency('appleframeworks', modules: 'Cocoa', required: get_option('cocoa'))
 elif targetos == 'sunos'
   socket = [cc.find_library('socket'),
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index f9ec8c84e9..eb8d06cbf5 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -686,4 +686,15 @@  char *qemu_get_host_name(Error **errp);
  */
 size_t qemu_get_host_physmem(void);
 
+/**
+ * iOS does not support system() so we replace it with an assertion failure.
+ */
+#ifdef CONFIG_IOS
+#define system ios_does_not_support_system
+static inline int ios_does_not_support_system(const char *command)
+{
+    assert(0);
+}
+#endif /* CONFIG_IOS */
+
 #endif
diff --git a/block.c b/block.c
index 8f177504d4..984a73a82c 100644
--- a/block.c
+++ b/block.c
@@ -54,7 +54,7 @@ 
 #ifdef CONFIG_BSD
 #include <sys/ioctl.h>
 #include <sys/queue.h>
-#ifndef __DragonFly__
+#if !defined(__DragonFly__) && !defined(CONFIG_IOS)
 #include <sys/disk.h>
 #endif
 #endif
diff --git a/block/file-posix.c b/block/file-posix.c
index c34bb9fac1..9f556322e6 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -181,7 +181,17 @@  typedef struct BDRVRawReopenState {
     bool check_cache_dropped;
 } BDRVRawReopenState;
 
-static int fd_open(BlockDriverState *bs);
+static int fd_open(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+
+    /* this is just to ensure s->fd is sane (its called by io ops) */
+    if (s->fd >= 0) {
+        return 0;
+    }
+    return -EIO;
+}
+
 static int64_t raw_getlength(BlockDriverState *bs);
 
 typedef struct RawPosixAIOData {
@@ -252,6 +262,12 @@  static int raw_normalize_devicepath(const char **filename, Error **errp)
 }
 #endif
 
+#if defined(CONFIG_IOS)
+static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
+{
+    return -ENOTSUP; /* not supported on iOS */
+}
+#else /* CONFIG_IOS */
 /*
  * Get logical block size via ioctl. On success store it in @sector_size_p.
  */
@@ -284,6 +300,7 @@  static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
 
     return success ? 0 : -errno;
 }
+#endif /* !CONFIG_IOS */
 
 /**
  * Get physical block size of @fd.
@@ -2307,7 +2324,7 @@  again:
         }
         if (size == 0)
 #endif
-#if defined(__APPLE__) && defined(__MACH__)
+#if !defined(CONFIG_IOS) && defined(__APPLE__) && defined(__MACH__)
         {
             uint64_t sectors = 0;
             uint32_t sector_size = 0;
@@ -3543,16 +3560,6 @@  hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 }
 #endif /* linux */
 
-static int fd_open(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-
-    /* this is just to ensure s->fd is sane (its called by io ops) */
-    if (s->fd >= 0)
-        return 0;
-    return -EIO;
-}
-
 static coroutine_fn int
 hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
 {
diff --git a/net/slirp.c b/net/slirp.c
index 77042e6df7..8413042c09 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -27,7 +27,7 @@ 
 #include "net/slirp.h"
 
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
 #include <pwd.h>
 #include <sys/wait.h>
 #endif
@@ -90,7 +90,7 @@  typedef struct SlirpState {
     Slirp *slirp;
     Notifier poll_notifier;
     Notifier exit_notifier;
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     gchar *smb_dir;
 #endif
     GSList *fwd;
@@ -103,7 +103,7 @@  static QTAILQ_HEAD(, SlirpState) slirp_stacks =
 static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp);
 static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp);
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
 static int slirp_smb(SlirpState *s, const char *exported_dir,
                      struct in_addr vserver_addr, Error **errp);
 static void slirp_smb_cleanup(SlirpState *s);
@@ -368,7 +368,7 @@  static int net_slirp_init(NetClientState *peer, const char *model,
     struct in6_addr ip6_prefix;
     struct in6_addr ip6_host;
     struct in6_addr ip6_dns;
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     struct in_addr smbsrv = { .s_addr = 0 };
 #endif
     NetClientState *nc;
@@ -478,7 +478,7 @@  static int net_slirp_init(NetClientState *peer, const char *model,
         return -1;
     }
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
         error_setg(errp, "Failed to parse SMB address");
         return -1;
@@ -593,7 +593,7 @@  static int net_slirp_init(NetClientState *peer, const char *model,
             }
         }
     }
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     if (smb_export) {
         if (slirp_smb(s, smb_export, smbsrv, errp) < 0) {
             goto error;
@@ -785,7 +785,7 @@  void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
 
 }
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
 
 /* automatic user mode samba server configuration */
 static void slirp_smb_cleanup(SlirpState *s)
@@ -900,7 +900,7 @@  static int slirp_smb(SlirpState* s, const char *exported_dir,
     return 0;
 }
 
-#endif /* !defined(_WIN32) */
+#endif /* !defined(_WIN32) && !defined(CONFIG_IOS) */
 
 static int guestfwd_can_read(void *opaque)
 {
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index c089e38120..81e40ac14a 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -34,6 +34,12 @@ 
 
 #ifndef CONFIG_HAS_ENVIRON
 #ifdef __APPLE__
+#include "TargetConditionals.h"
+#if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+#define APPLE_USE_CRT_EXTERNS
+#endif
+#endif
+#ifdef APPLE_USE_CRT_EXTERNS
 #include <crt_externs.h>
 #define environ (*_NSGetEnviron())
 #else
diff --git a/MAINTAINERS b/MAINTAINERS
index ce5ef9bde6..3baf289a1d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -538,6 +538,13 @@  F: include/*/*win32*
 X: qga/*win32*
 F: qemu.nsi
 
+IOS
+M: Joelle van Dyne <j@getutm.app>
+S: Maintained
+K: ^Subject:.*(?i)iOS
+F: docs/devel/ios.rst
+F: include/tcg/tcg-apple-jit.h
+
 Alpha Machines
 --------------
 M: Richard Henderson <richard.henderson@linaro.org>
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 6a67c538be..42b46a7ca4 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -46,12 +46,11 @@  qtests_i386 = \
   (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-test'] : []) +              \
   (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-swtpm-test'] : []) +        \
   (config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) +              \
+  (not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test', 'hd-geo-test'] : []) +      \
   qtests_pci +                                                                              \
   ['fdc-test',
    'ide-test',
-   'hd-geo-test',
    'boot-order-test',
-   'bios-tables-test',
    'rtc-test',
    'i440fx-test',
    'fuzz-test',
@@ -148,9 +147,9 @@  qtests_arm = \
    'boot-serial-test',
    'hexloader-test']
 
-# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional
+# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional (except on iOS)
 qtests_aarch64 = \
-  (cpu != 'arm' ? ['bios-tables-test'] : []) +                                                  \
+  (cpu != 'arm' and not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test'] : []) +        \
   (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) +        \
   (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) +  \
   ['arm-cpu-features',