86 changes: 84 additions & 2 deletions qemu-options.hx
Expand Up @@ -2882,6 +2882,19 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
" VALE port (created on the fly) called 'name' ('nmname' is name of the \n"
" netmap device, defaults to '/dev/netmap')\n"
#endif
#ifdef CONFIG_AF_XDP
"-netdev af-xdp,id=str,ifname=name[,mode=native|skb][,force-copy=on|off]\n"
" [,queues=n][,start-queue=m][,inhibit=on|off][,sock-fds=x:y:...:z]\n"
" attach to the existing network interface 'name' with AF_XDP socket\n"
" use 'mode=MODE' to specify an XDP program attach mode\n"
" use 'force-copy=on|off' to force XDP copy mode even if device supports zero-copy (default: off)\n"
" use 'inhibit=on|off' to inhibit loading of a default XDP program (default: off)\n"
" with inhibit=on,\n"
" use 'sock-fds' to provide file descriptors for already open AF_XDP sockets\n"
" added to a socket map in XDP program. One socket per queue.\n"
" use 'queues=n' to specify how many queues of a multiqueue interface should be used\n"
" use 'start-queue=m' to specify the first queue that should be used\n"
#endif
#ifdef CONFIG_POSIX
"-netdev vhost-user,id=str,chardev=dev[,vhostforce=on|off]\n"
" configure a vhost-user network, backed by a chardev 'dev'\n"
Expand Down Expand Up @@ -2927,6 +2940,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
#ifdef CONFIG_NETMAP
"netmap|"
#endif
#ifdef CONFIG_AF_XDP
"af-xdp|"
#endif
#ifdef CONFIG_POSIX
"vhost-user|"
#endif
Expand Down Expand Up @@ -2955,14 +2971,17 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
#ifdef CONFIG_NETMAP
"netmap|"
#endif
#ifdef CONFIG_AF_XDP
"af-xdp|"
#endif
#ifdef CONFIG_VMNET
"vmnet-host|vmnet-shared|vmnet-bridged|"
#endif
"socket][,option][,option][,...]\n"
" old way to initialize a host network interface\n"
" (use the -netdev option if possible instead)\n", QEMU_ARCH_ALL)
SRST
``-nic [tap|bridge|user|l2tpv3|vde|netmap|vhost-user|socket][,...][,mac=macaddr][,model=mn]``
``-nic [tap|bridge|user|l2tpv3|vde|netmap|af-xdp|vhost-user|socket][,...][,mac=macaddr][,model=mn]``
This option is a shortcut for configuring both the on-board
(default) guest NIC hardware and the host network backend in one go.
The host backend options are the same as with the corresponding
Expand Down Expand Up @@ -3376,6 +3395,55 @@ SRST
# launch QEMU instance
|qemu_system| linux.img -nic vde,sock=/tmp/myswitch
``-netdev af-xdp,id=str,ifname=name[,mode=native|skb][,force-copy=on|off][,queues=n][,start-queue=m][,inhibit=on|off][,sock-fds=x:y:...:z]``
Configure AF_XDP backend to connect to a network interface 'name'
using AF_XDP socket. A specific program attach mode for a default
XDP program can be forced with 'mode', defaults to best-effort,
where the likely most performant mode will be in use. Number of queues
'n' should generally match the number or queues in the interface,
defaults to 1. Traffic arriving on non-configured device queues will
not be delivered to the network backend.
.. parsed-literal::
# set number of queues to 4
ethtool -L eth0 combined 4
# launch QEMU instance
|qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
-netdev af-xdp,id=n1,ifname=eth0,queues=4
'start-queue' option can be specified if a particular range of queues
[m, m + n] should be in use. For example, this is may be necessary in
order to use certain NICs in native mode. Kernel allows the driver to
create a separate set of XDP queues on top of regular ones, and only
these queues can be used for AF_XDP sockets. NICs that work this way
may also require an additional traffic redirection with ethtool to these
special queues.
.. parsed-literal::
# set number of queues to 1
ethtool -L eth0 combined 1
# redirect all the traffic to the second queue (id: 1)
# note: drivers may require non-empty key/mask pair.
ethtool -N eth0 flow-type ether \\
dst 00:00:00:00:00:00 m FF:FF:FF:FF:FF:FE action 1
ethtool -N eth0 flow-type ether \\
dst 00:00:00:00:00:01 m FF:FF:FF:FF:FF:FE action 1
# launch QEMU instance
|qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
-netdev af-xdp,id=n1,ifname=eth0,queues=1,start-queue=1
XDP program can also be loaded externally. In this case 'inhibit' option
should be set to 'on' and 'sock-fds' provided with file descriptors for
already open but not bound XDP sockets already added to a socket map for
corresponding queues. One socket per queue.
.. parsed-literal::
|qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
-netdev af-xdp,id=n1,ifname=eth0,queues=3,inhibit=on,sock-fds=15:16:17
``-netdev vhost-user,chardev=id[,vhostforce=on|off][,queues=n]``
Establish a vhost-user netdev, backed by a chardev id. The chardev
should be a unix domain socket backed one. The vhost-user uses a
Expand Down Expand Up @@ -4995,7 +5063,7 @@ SRST
they are specified. Note that the 'id' property must be set. These
objects are placed in the '/objects' path.

``-object memory-backend-file,id=id,size=size,mem-path=dir,share=on|off,discard-data=on|off,merge=on|off,dump=on|off,prealloc=on|off,host-nodes=host-nodes,policy=default|preferred|bind|interleave,align=align,offset=offset,readonly=on|off``
``-object memory-backend-file,id=id,size=size,mem-path=dir,share=on|off,discard-data=on|off,merge=on|off,dump=on|off,prealloc=on|off,host-nodes=host-nodes,policy=default|preferred|bind|interleave,align=align,offset=offset,readonly=on|off,rom=on|off|auto``
Creates a memory file backend object, which can be used to back
the guest RAM with huge pages.

Expand Down Expand Up @@ -5085,6 +5153,20 @@ SRST
The ``readonly`` option specifies whether the backing file is opened
read-only or read-write (default).

The ``rom`` option specifies whether to create Read Only Memory
(ROM) that cannot be modified by the VM. Any write attempts to such
ROM will be denied. Most use cases want proper RAM instead of ROM.
However, selected use cases, like R/O NVDIMMs, can benefit from
ROM. If set to ``on``, create ROM; if set to ``off``, create
writable RAM; if set to ``auto`` (default), the value of the
``readonly`` option is used. This option is primarily helpful when
we want to have writable RAM in configurations that would
traditionally create ROM before the ``rom`` option was introduced:
VM templating, where we want to open a file readonly
(``readonly=on``) and mark the memory to be private for QEMU
(``share=off``). For this use case, we need writable RAM instead
of ROM, and want to also set ``rom=off``.

``-object memory-backend-ram,id=id,merge=on|off,dump=on|off,share=on|off,prealloc=on|off,size=size,host-nodes=host-nodes,policy=default|preferred|bind|interleave``
Creates a memory backend object, which can be used to back the
guest RAM. Memory backend objects offer more control than the
Expand Down
2 changes: 1 addition & 1 deletion roms/edk2
Submodule edk2 updated from f80f05 to 819cfc
12 changes: 10 additions & 2 deletions roms/edk2-build.config
Expand Up @@ -26,6 +26,9 @@ DEBUG_PRINT_ERROR_LEVEL = 0x80000000
# grub.efi uses EfiLoaderData for code
PcdDxeNxMemoryProtectionPolicy = 0xC000000000007FD1

[pcds.workaround.202308]
PcdFirstTimeWakeUpAPsBySipi = FALSE

####################################################################################
# i386

Expand Down Expand Up @@ -57,6 +60,7 @@ desc = ovmf build (64-bit)
conf = OvmfPkg/OvmfPkgX64.dsc
arch = X64
opts = common
pcds = workaround.202308
plat = OvmfX64
dest = ../pc-bios
cpy1 = FV/OVMF_CODE.fd edk2-x86_64-code.fd
Expand All @@ -67,6 +71,7 @@ conf = OvmfPkg/OvmfPkgIa32X64.dsc
arch = IA32 X64
opts = common
ovmf.sb.smm
pcds = workaround.202308
plat = Ovmf3264
dest = ../pc-bios
cpy1 = FV/OVMF_CODE.fd edk2-x86_64-secure-code.fd
Expand All @@ -76,6 +81,7 @@ desc = ovmf build for microvm
conf = OvmfPkg/Microvm/MicrovmX64.dsc
arch = X64
opts = common
pcds = workaround.202308
plat = MicrovmX64
dest = ../pc-bios
cpy1 = FV/MICROVM.fd edk2-x86_64-microvm.fd
Expand Down Expand Up @@ -120,5 +126,7 @@ conf = OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
arch = RISCV64
plat = RiscVVirtQemu
dest = ../pc-bios
cpy1 = FV/RISCV_VIRT.fd edk2-riscv.fd
pad1 = edk2-riscv.fd 32m
cpy1 = FV/RISCV_VIRT_CODE.fd edk2-riscv-code.fd
cpy2 = FV/RISCV_VIRT_VARS.fd edk2-riscv-vars.fd
pad1 = edk2-riscv-code.fd 32m
pad2 = edk2-riscv-vars.fd 32m
202 changes: 128 additions & 74 deletions roms/edk2-build.py
Expand Up @@ -6,6 +6,7 @@
"""
import os
import sys
import time
import shutil
import argparse
import subprocess
Expand Down Expand Up @@ -45,19 +46,28 @@ def get_coredir(cfg):
return os.path.abspath(cfg['global']['core'])
return os.getcwd()

def get_version(cfg):
def get_toolchain(cfg, build):
if cfg.has_option(build, 'tool'):
return cfg[build]['tool']
if cfg.has_option('global', 'tool'):
return cfg['global']['tool']
return 'GCC5'

def get_version(cfg, silent = False):
coredir = get_coredir(cfg)
if version_override:
version = version_override
print('')
print(f'### version [override]: {version}')
if not silent:
print('')
print(f'### version [override]: {version}')
return version
if os.environ.get('RPM_PACKAGE_NAME'):
version = os.environ.get('RPM_PACKAGE_NAME')
version += '-' + os.environ.get('RPM_PACKAGE_VERSION')
version += '-' + os.environ.get('RPM_PACKAGE_RELEASE')
print('')
print(f'### version [rpmbuild]: {version}')
if not silent:
print('')
print(f'### version [rpmbuild]: {version}')
return version
if os.path.exists(coredir + '/.git'):
cmdline = [ 'git', 'describe', '--tags', '--abbrev=8',
Expand All @@ -66,16 +76,17 @@ def get_version(cfg):
stdout = subprocess.PIPE,
check = True)
version = result.stdout.decode().strip()
print('')
print(f'### version [git]: {version}')
if not silent:
print('')
print(f'### version [git]: {version}')
return version
return None

def pcd_string(name, value):
return f'{name}=L{value}\\0'

def pcd_version(cfg):
version = get_version(cfg)
def pcd_version(cfg, silent = False):
version = get_version(cfg, silent)
if version is None:
return []
return [ '--pcd', pcd_string('PcdFirmwareVersionString', version) ]
Expand All @@ -85,49 +96,58 @@ def pcd_release_date():
return []
return [ '--pcd', pcd_string('PcdFirmwareReleaseDateString', release_date) ]

def build_message(line, line2 = None):
def build_message(line, line2 = None, silent = False):
if os.environ.get('TERM') in [ 'xterm', 'xterm-256color' ]:
# setxterm title
start = '\x1b]2;'
end = '\x07'
print(f'{start}{rebase_prefix}{line}{end}', end = '')

print('')
print('###')
print(f'### {rebase_prefix}{line}')
if line2:
print(f'### {line2}')
print('###', flush = True)
if silent:
print(f'### {rebase_prefix}{line}', flush = True)
else:
print('')
print('###')
print(f'### {rebase_prefix}{line}')
if line2:
print(f'### {line2}')
print('###', flush = True)

def build_run(cmdline, name, section, silent = False):
print(cmdline, flush = True)
def build_run(cmdline, name, section, silent = False, nologs = False):
if silent:
print('### building in silent mode ...', flush = True)
logfile = f'{section}.log'
if nologs:
print(f'### building in silent mode [no log] ...', flush = True)
else:
print(f'### building in silent mode [{logfile}] ...', flush = True)
start = time.time()
result = subprocess.run(cmdline, check = False,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT)

logfile = f'{section}.log'
print(f'### writing log to {logfile} ...')
with open(logfile, 'wb') as f:
f.write(result.stdout)
if not nologs:
with open(logfile, 'wb') as f:
f.write(result.stdout)

if result.returncode:
print('### BUILD FAILURE')
print('### cmdline')
print(cmdline)
print('### output')
print(result.stdout.decode())
print(f'### exit code: {result.returncode}')
else:
print('### OK')
secs = int(time.time() - start)
print(f'### OK ({int(secs/60)}:{secs%60:02d})')
else:
print(cmdline, flush = True)
result = subprocess.run(cmdline, check = False)
if result.returncode:
print(f'ERROR: {cmdline[0]} exited with {result.returncode}'
f' while building {name}')
sys.exit(result.returncode)

def build_copy(plat, tgt, dstdir, copy):
srcdir = f'Build/{plat}/{tgt}_GCC5'
def build_copy(plat, tgt, toolchain, dstdir, copy):
srcdir = f'Build/{plat}/{tgt}_{toolchain}'
names = copy.split()
srcfile = names[0]
if len(names) > 1:
Expand Down Expand Up @@ -156,74 +176,76 @@ def pad_file(dstdir, pad):
subprocess.run(cmdline, check = True)

# pylint: disable=too-many-branches
def build_one(cfg, build, jobs = None, silent = False):
def build_one(cfg, build, jobs = None, silent = False, nologs = False):
b = cfg[build]

cmdline = [ 'build' ]
cmdline += [ '-t', 'GCC5' ]
cmdline += [ '-p', cfg[build]['conf'] ]
cmdline += [ '-t', get_toolchain(cfg, build) ]
cmdline += [ '-p', b['conf'] ]

if (cfg[build]['conf'].startswith('OvmfPkg/') or
cfg[build]['conf'].startswith('ArmVirtPkg/')):
cmdline += pcd_version(cfg)
if (b['conf'].startswith('OvmfPkg/') or
b['conf'].startswith('ArmVirtPkg/')):
cmdline += pcd_version(cfg, silent)
cmdline += pcd_release_date()

if jobs:
cmdline += [ '-n', jobs ]
for arch in cfg[build]['arch'].split():
for arch in b['arch'].split():
cmdline += [ '-a', arch ]
if 'opts' in cfg[build]:
for name in cfg[build]['opts'].split():
if 'opts' in b:
for name in b['opts'].split():
section = 'opts.' + name
for opt in cfg[section]:
cmdline += [ '-D', opt + '=' + cfg[section][opt] ]
if 'pcds' in cfg[build]:
for name in cfg[build]['pcds'].split():
if 'pcds' in b:
for name in b['pcds'].split():
section = 'pcds.' + name
for pcd in cfg[section]:
cmdline += [ '--pcd', pcd + '=' + cfg[section][pcd] ]
if 'tgts' in cfg[build]:
tgts = cfg[build]['tgts'].split()
if 'tgts' in b:
tgts = b['tgts'].split()
else:
tgts = [ 'DEBUG' ]
for tgt in tgts:
desc = None
if 'desc' in cfg[build]:
desc = cfg[build]['desc']
build_message(f'building: {cfg[build]["conf"]} ({cfg[build]["arch"]}, {tgt})',
f'description: {desc}')
if 'desc' in b:
desc = b['desc']
build_message(f'building: {b["conf"]} ({b["arch"]}, {tgt})',
f'description: {desc}',
silent = silent)
build_run(cmdline + [ '-b', tgt ],
cfg[build]['conf'],
b['conf'],
build + '.' + tgt,
silent)
silent,
nologs)

if 'plat' in cfg[build]:
if 'plat' in b:
# copy files
for cpy in cfg[build]:
for cpy in b:
if not cpy.startswith('cpy'):
continue
build_copy(cfg[build]['plat'],
tgt,
cfg[build]['dest'],
cfg[build][cpy])
build_copy(b['plat'], tgt,
get_toolchain(cfg, build),
b['dest'], b[cpy])
# pad builds
for pad in cfg[build]:
for pad in b:
if not pad.startswith('pad'):
continue
pad_file(cfg[build]['dest'],
cfg[build][pad])
pad_file(b['dest'], b[pad])

def build_basetools(silent = False):
build_message('building: BaseTools')
def build_basetools(silent = False, nologs = False):
build_message('building: BaseTools', silent = silent)
basedir = os.environ['EDK_TOOLS_PATH']
cmdline = [ 'make', '-C', basedir ]
build_run(cmdline, 'BaseTools', 'build.basetools', silent)
build_run(cmdline, 'BaseTools', 'build.basetools', silent, nologs)

def binary_exists(name):
for pdir in os.environ['PATH'].split(':'):
if os.path.exists(pdir + '/' + name):
return True
return False

def prepare_env(cfg):
def prepare_env(cfg, silent = False):
""" mimic Conf/BuildEnv.sh """
workspace = os.getcwd()
packages = [ workspace, ]
Expand Down Expand Up @@ -253,7 +275,7 @@ def prepare_env(cfg):
toolsdef = coredir + '/Conf/tools_def.txt'
if not os.path.exists(toolsdef):
os.makedirs(os.path.dirname(toolsdef), exist_ok = True)
build_message('running BaseTools/BuildEnv')
build_message('running BaseTools/BuildEnv', silent = silent)
cmdline = [ 'bash', 'BaseTools/BuildEnv' ]
subprocess.run(cmdline, cwd = coredir, check = True)

Expand All @@ -267,20 +289,32 @@ def prepare_env(cfg):
os.environ['PYTHONHASHSEED'] = '1'

# for cross builds
if binary_exists('arm-linux-gnu-gcc'):
if binary_exists('arm-linux-gnueabi-gcc'):
# ubuntu
os.environ['GCC5_ARM_PREFIX'] = 'arm-linux-gnueabi-'
os.environ['GCC_ARM_PREFIX'] = 'arm-linux-gnueabi-'
elif binary_exists('arm-linux-gnu-gcc'):
# fedora
os.environ['GCC5_ARM_PREFIX'] = 'arm-linux-gnu-'
os.environ['GCC_ARM_PREFIX'] = 'arm-linux-gnu-'
if binary_exists('loongarch64-linux-gnu-gcc'):
os.environ['GCC5_LOONGARCH64_PREFIX'] = 'loongarch64-linux-gnu-'
os.environ['GCC_LOONGARCH64_PREFIX'] = 'loongarch64-linux-gnu-'

hostarch = os.uname().machine
if binary_exists('aarch64-linux-gnu-gcc') and hostarch != 'aarch64':
os.environ['GCC5_AARCH64_PREFIX'] = 'aarch64-linux-gnu-'
os.environ['GCC_AARCH64_PREFIX'] = 'aarch64-linux-gnu-'
if binary_exists('riscv64-linux-gnu-gcc') and hostarch != 'riscv64':
os.environ['GCC5_RISCV64_PREFIX'] = 'riscv64-linux-gnu-'
os.environ['GCC_RISCV64_PREFIX'] = 'riscv64-linux-gnu-'
if binary_exists('x86_64-linux-gnu-gcc') and hostarch != 'x86_64':
os.environ['GCC5_IA32_PREFIX'] = 'x86_64-linux-gnu-'
os.environ['GCC5_X64_PREFIX'] = 'x86_64-linux-gnu-'
os.environ['GCC5_BIN'] = 'x86_64-linux-gnu-'
os.environ['GCC_IA32_PREFIX'] = 'x86_64-linux-gnu-'
os.environ['GCC_X64_PREFIX'] = 'x86_64-linux-gnu-'
os.environ['GCC_BIN'] = 'x86_64-linux-gnu-'

def build_list(cfg):
for build in cfg.sections():
Expand All @@ -303,10 +337,12 @@ def main():
parser.add_argument('-j', '--jobs', dest = 'jobs', type = str,
help = 'allow up to JOBS parallel build jobs',
metavar = 'JOBS')
parser.add_argument('-m', '--match', dest = 'match', type = str,
parser.add_argument('-m', '--match', dest = 'match',
type = str, action = 'append',
help = 'only run builds matching INCLUDE (substring)',
metavar = 'INCLUDE')
parser.add_argument('-x', '--exclude', dest = 'exclude', type = str,
parser.add_argument('-x', '--exclude', dest = 'exclude',
type = str, action = 'append',
help = 'skip builds matching EXCLUDE (substring)',
metavar = 'EXCLUDE')
parser.add_argument('-l', '--list', dest = 'list',
Expand All @@ -316,13 +352,19 @@ def main():
action = 'store_true', default = False,
help = 'write build output to logfiles, '
'write to console only on errors')
parser.add_argument('--no-logs', dest = 'nologs',
action = 'store_true', default = False,
help = 'do not write build log files (with --silent)')
parser.add_argument('--core', dest = 'core', type = str, metavar = 'DIR',
help = 'location of the core edk2 repository '
'(i.e. where BuildTools are located)')
parser.add_argument('--pkg', '--package', dest = 'pkgs',
type = str, action = 'append', metavar = 'DIR',
help = 'location(s) of additional packages '
'(can be specified multiple times)')
parser.add_argument('-t', '--toolchain', dest = 'toolchain',
type = str, metavar = 'NAME',
help = 'tool chain to be used to build edk2')
parser.add_argument('--version-override', dest = 'version_override',
type = str, metavar = 'VERSION',
help = 'set firmware build version')
Expand All @@ -335,7 +377,7 @@ def main():
os.chdir(options.directory)

if not os.path.exists(options.configfile):
print('config file "{options.configfile}" not found')
print(f'config file "{options.configfile}" not found')
return 1

cfg = configparser.ConfigParser()
Expand All @@ -344,14 +386,16 @@ def main():

if options.list:
build_list(cfg)
return
return 0

if not cfg.has_section('global'):
cfg.add_section('global')
if options.core:
cfg.set('global', 'core', options.core)
if options.pkgs:
cfg.set('global', 'pkgs', ' '.join(options.pkgs))
if options.toolchain:
cfg.set('global', 'tool', options.toolchain)

global version_override
global release_date
Expand All @@ -361,18 +405,28 @@ def main():
if options.release_date:
release_date = options.release_date

prepare_env(cfg)
build_basetools(options.silent)
prepare_env(cfg, options.silent)
build_basetools(options.silent, options.nologs)
for build in cfg.sections():
if not build.startswith('build.'):
continue
if options.match and options.match not in build:
print(f'# skipping "{build}" (not matching "{options.match}")')
continue
if options.exclude and options.exclude in build:
print(f'# skipping "{build}" (matching "{options.exclude}")')
continue
build_one(cfg, build, options.jobs, options.silent)
if options.match:
matching = False
for item in options.match:
if item in build:
matching = True
if not matching:
print(f'# skipping "{build}" (not matching "{"|".join(options.match)}")')
continue
if options.exclude:
exclude = False
for item in options.exclude:
if item in build:
print(f'# skipping "{build}" (matching "{item}")')
exclude = True
if exclude:
continue
build_one(cfg, build, options.jobs, options.silent, options.nologs)

return 0

Expand Down
1 change: 1 addition & 0 deletions scripts/ci/org.centos/stream/8/x86_64/configure
Expand Up @@ -35,6 +35,7 @@
--block-drv-ro-whitelist="vmdk,vhdx,vpc,https,ssh" \
--with-coroutine=ucontext \
--tls-priority=@QEMU,SYSTEM \
--disable-af-xdp \
--disable-attr \
--disable-auth-pam \
--disable-avx2 \
Expand Down
3 changes: 3 additions & 0 deletions scripts/meson-buildoptions.sh
Expand Up @@ -76,6 +76,7 @@ meson_options_help() {
printf "%s\n" 'disabled with --disable-FEATURE, default is enabled if available'
printf "%s\n" '(unless built with --without-default-features):'
printf "%s\n" ''
printf "%s\n" ' af-xdp AF_XDP network backend support'
printf "%s\n" ' alsa ALSA sound support'
printf "%s\n" ' attr attr/xattr support'
printf "%s\n" ' auth-pam PAM access control'
Expand Down Expand Up @@ -208,6 +209,8 @@ meson_options_help() {
}
_meson_option_parse() {
case $1 in
--enable-af-xdp) printf "%s" -Daf_xdp=enabled ;;
--disable-af-xdp) printf "%s" -Daf_xdp=disabled ;;
--enable-alsa) printf "%s" -Dalsa=enabled ;;
--disable-alsa) printf "%s" -Dalsa=disabled ;;
--enable-attr) printf "%s" -Dattr=enabled ;;
Expand Down
3 changes: 0 additions & 3 deletions softmmu/async-teardown.c
Expand Up @@ -121,10 +121,7 @@ static void *new_stack_for_clone(void)

/* Allocate a new stack and get a pointer to its top. */
stack_ptr = qemu_alloc_stack(&stack_size);
#if !defined(HOST_HPPA)
/* The top is at the end of the area, except on HPPA. */
stack_ptr += stack_size;
#endif

return stack_ptr;
}
Expand Down
20 changes: 16 additions & 4 deletions softmmu/memory.c
Expand Up @@ -842,6 +842,10 @@ static void address_space_update_ioeventfds(AddressSpace *as)
AddrRange tmp;
unsigned i;

if (!as->ioeventfd_notifiers) {
return;
}

/*
* It is likely that the number of ioeventfds hasn't changed much, so use
* the previous size as the starting value, with some headroom to avoid
Expand Down Expand Up @@ -1620,18 +1624,17 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
uint32_t ram_flags,
const char *path,
ram_addr_t offset,
bool readonly,
Error **errp)
{
Error *err = NULL;
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->readonly = readonly;
mr->readonly = !!(ram_flags & RAM_READONLY);
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->align = align;
mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path,
offset, readonly, &err);
offset, &err);
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
Expand All @@ -1651,10 +1654,11 @@ void memory_region_init_ram_from_fd(MemoryRegion *mr,
Error *err = NULL;
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->readonly = !!(ram_flags & RAM_READONLY);
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset,
false, &err);
&err);
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
Expand Down Expand Up @@ -3075,6 +3079,10 @@ void memory_listener_register(MemoryListener *listener, AddressSpace *as)
}

listener_add_address_space(listener, as);

if (listener->eventfd_add || listener->eventfd_del) {
as->ioeventfd_notifiers++;
}
}

void memory_listener_unregister(MemoryListener *listener)
Expand All @@ -3083,6 +3091,10 @@ void memory_listener_unregister(MemoryListener *listener)
return;
}

if (listener->eventfd_add || listener->eventfd_del) {
listener->address_space->ioeventfd_notifiers--;
}

listener_del_address_space(listener, listener->address_space);
QTAILQ_REMOVE(&memory_listeners, listener, link);
QTAILQ_REMOVE(&listener->address_space->listeners, listener, link_as);
Expand Down
93 changes: 72 additions & 21 deletions softmmu/physmem.c
Expand Up @@ -1288,8 +1288,7 @@ static int64_t get_file_align(int fd)
static int file_ram_open(const char *path,
const char *region_name,
bool readonly,
bool *created,
Error **errp)
bool *created)
{
char *filename;
char *sanitized_name;
Expand All @@ -1300,10 +1299,33 @@ static int file_ram_open(const char *path,
for (;;) {
fd = open(path, readonly ? O_RDONLY : O_RDWR);
if (fd >= 0) {
/*
* open(O_RDONLY) won't fail with EISDIR. Check manually if we
* opened a directory and fail similarly to how we fail ENOENT
* in readonly mode. Note that mkstemp() would imply O_RDWR.
*/
if (readonly) {
struct stat file_stat;

if (fstat(fd, &file_stat)) {
close(fd);
if (errno == EINTR) {
continue;
}
return -errno;
} else if (S_ISDIR(file_stat.st_mode)) {
close(fd);
return -EISDIR;
}
}
/* @path names an existing file, use it */
break;
}
if (errno == ENOENT) {
if (readonly) {
/* Refuse to create new, readonly files. */
return -ENOENT;
}
/* @path names a file that doesn't exist, create it */
fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
if (fd >= 0) {
Expand Down Expand Up @@ -1333,10 +1355,7 @@ static int file_ram_open(const char *path,
g_free(filename);
}
if (errno != EEXIST && errno != EINTR) {
error_setg_errno(errp, errno,
"can't open backing store %s for guest RAM",
path);
return -1;
return -errno;
}
/*
* Try again on EINTR and EEXIST. The latter happens when
Expand All @@ -1350,7 +1369,6 @@ static int file_ram_open(const char *path,
static void *file_ram_alloc(RAMBlock *block,
ram_addr_t memory,
int fd,
bool readonly,
bool truncate,
off_t offset,
Error **errp)
Expand Down Expand Up @@ -1408,7 +1426,7 @@ static void *file_ram_alloc(RAMBlock *block,
perror("ftruncate");
}

qemu_map_flags = readonly ? QEMU_MAP_READONLY : 0;
qemu_map_flags = (block->flags & RAM_READONLY) ? QEMU_MAP_READONLY : 0;
qemu_map_flags |= (block->flags & RAM_SHARED) ? QEMU_MAP_SHARED : 0;
qemu_map_flags |= (block->flags & RAM_PMEM) ? QEMU_MAP_SYNC : 0;
qemu_map_flags |= (block->flags & RAM_NORESERVE) ? QEMU_MAP_NORESERVE : 0;
Expand Down Expand Up @@ -1876,15 +1894,16 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
#ifdef CONFIG_POSIX
RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
uint32_t ram_flags, int fd, off_t offset,
bool readonly, Error **errp)
Error **errp)
{
RAMBlock *new_block;
Error *local_err = NULL;
int64_t file_size, file_align;

/* Just support these ram flags by now. */
assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
RAM_PROTECTED | RAM_NAMED_FILE)) == 0);
RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY |
RAM_READONLY_FD)) == 0);

if (xen_enabled()) {
error_setg(errp, "-mem-path not supported with Xen");
Expand Down Expand Up @@ -1919,8 +1938,8 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
new_block->used_length = size;
new_block->max_length = size;
new_block->flags = ram_flags;
new_block->host = file_ram_alloc(new_block, size, fd, readonly,
!file_size, offset, errp);
new_block->host = file_ram_alloc(new_block, size, fd, !file_size, offset,
errp);
if (!new_block->host) {
g_free(new_block);
return NULL;
Expand All @@ -1939,20 +1958,40 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,

RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
uint32_t ram_flags, const char *mem_path,
off_t offset, bool readonly, Error **errp)
off_t offset, Error **errp)
{
int fd;
bool created;
RAMBlock *block;

fd = file_ram_open(mem_path, memory_region_name(mr), readonly, &created,
errp);
fd = file_ram_open(mem_path, memory_region_name(mr),
!!(ram_flags & RAM_READONLY_FD), &created);
if (fd < 0) {
error_setg_errno(errp, -fd, "can't open backing store %s for guest RAM",
mem_path);
if (!(ram_flags & RAM_READONLY_FD) && !(ram_flags & RAM_SHARED) &&
fd == -EACCES) {
/*
* If we can open the file R/O (note: will never create a new file)
* and we are dealing with a private mapping, there are still ways
* to consume such files and get RAM instead of ROM.
*/
fd = file_ram_open(mem_path, memory_region_name(mr), true,
&created);
if (fd < 0) {
return NULL;
}
assert(!created);
close(fd);
error_append_hint(errp, "Consider opening the backing store"
" read-only but still creating writable RAM using"
" '-object memory-backend-file,readonly=on,rom=off...'"
" (see \"VM templating\" documentation)\n");
}
return NULL;
}

block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset, readonly,
errp);
block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset, errp);
if (!block) {
if (created) {
unlink(mem_path);
Expand Down Expand Up @@ -2070,6 +2109,7 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
ram_addr_t offset;
int flags;
void *area, *vaddr;
int prot;

RAMBLOCK_FOREACH(block) {
offset = addr - block->offset;
Expand All @@ -2084,13 +2124,14 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
flags |= block->flags & RAM_SHARED ?
MAP_SHARED : MAP_PRIVATE;
flags |= block->flags & RAM_NORESERVE ? MAP_NORESERVE : 0;
prot = PROT_READ;
prot |= block->flags & RAM_READONLY ? 0 : PROT_WRITE;
if (block->fd >= 0) {
area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
flags, block->fd, offset + block->fd_offset);
area = mmap(vaddr, length, prot, flags, block->fd,
offset + block->fd_offset);
} else {
flags |= MAP_ANONYMOUS;
area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
flags, -1, 0);
area = mmap(vaddr, length, prot, flags, -1, 0);
}
if (area != vaddr) {
error_report("Could not remap addr: "
Expand Down Expand Up @@ -3480,6 +3521,16 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
* so a userfault will trigger.
*/
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
/*
* fallocate() will fail with readonly files. Let's print a
* proper error message.
*/
if (rb->flags & RAM_READONLY_FD) {
error_report("ram_block_discard_range: Discarding RAM"
" with readonly files is not supported");
goto err;

}
/*
* We'll discard data from the actual file, even though we only
* have a MAP_PRIVATE mapping, possibly messing with other
Expand Down
58 changes: 10 additions & 48 deletions target/arm/tcg/translate.c
Expand Up @@ -2943,54 +2943,16 @@ void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
gen_gvec_fn3_qc(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, fns[vece - 1]);
}

#define GEN_CMP0(NAME, COND) \
static void gen_##NAME##0_i32(TCGv_i32 d, TCGv_i32 a) \
{ \
tcg_gen_negsetcond_i32(COND, d, a, tcg_constant_i32(0)); \
} \
static void gen_##NAME##0_i64(TCGv_i64 d, TCGv_i64 a) \
{ \
tcg_gen_negsetcond_i64(COND, d, a, tcg_constant_i64(0)); \
} \
static void gen_##NAME##0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) \
{ \
TCGv_vec zero = tcg_constant_vec_matching(d, vece, 0); \
tcg_gen_cmp_vec(COND, vece, d, a, zero); \
} \
void gen_gvec_##NAME##0(unsigned vece, uint32_t d, uint32_t m, \
uint32_t opr_sz, uint32_t max_sz) \
{ \
const GVecGen2 op[4] = { \
{ .fno = gen_helper_gvec_##NAME##0_b, \
.fniv = gen_##NAME##0_vec, \
.opt_opc = vecop_list_cmp, \
.vece = MO_8 }, \
{ .fno = gen_helper_gvec_##NAME##0_h, \
.fniv = gen_##NAME##0_vec, \
.opt_opc = vecop_list_cmp, \
.vece = MO_16 }, \
{ .fni4 = gen_##NAME##0_i32, \
.fniv = gen_##NAME##0_vec, \
.opt_opc = vecop_list_cmp, \
.vece = MO_32 }, \
{ .fni8 = gen_##NAME##0_i64, \
.fniv = gen_##NAME##0_vec, \
.opt_opc = vecop_list_cmp, \
.prefer_i64 = TCG_TARGET_REG_BITS == 64, \
.vece = MO_64 }, \
}; \
tcg_gen_gvec_2(d, m, opr_sz, max_sz, &op[vece]); \
}

static const TCGOpcode vecop_list_cmp[] = {
INDEX_op_cmp_vec, 0
};

GEN_CMP0(ceq, TCG_COND_EQ)
GEN_CMP0(cle, TCG_COND_LE)
GEN_CMP0(cge, TCG_COND_GE)
GEN_CMP0(clt, TCG_COND_LT)
GEN_CMP0(cgt, TCG_COND_GT)
#define GEN_CMP0(NAME, COND) \
void NAME(unsigned vece, uint32_t d, uint32_t m, \
uint32_t opr_sz, uint32_t max_sz) \
{ tcg_gen_gvec_cmpi(COND, vece, d, m, 0, opr_sz, max_sz); }

GEN_CMP0(gen_gvec_ceq0, TCG_COND_EQ)
GEN_CMP0(gen_gvec_cle0, TCG_COND_LE)
GEN_CMP0(gen_gvec_cge0, TCG_COND_GE)
GEN_CMP0(gen_gvec_clt0, TCG_COND_LT)
GEN_CMP0(gen_gvec_cgt0, TCG_COND_GT)

#undef GEN_CMP0

Expand Down
59 changes: 44 additions & 15 deletions tcg/aarch64/tcg-target.c.inc
Expand Up @@ -272,7 +272,7 @@ static bool is_shimm1632(uint32_t v32, int *cmode, int *imm8)
}
}

static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -602,6 +602,10 @@ typedef enum {
DMB_ISH = 0xd50338bf,
DMB_LD = 0x00000100,
DMB_ST = 0x00000200,

BTI_C = 0xd503245f,
BTI_J = 0xd503249f,
BTI_JC = 0xd50324df,
} AArch64Insn;

static inline uint32_t tcg_in32(TCGContext *s)
Expand Down Expand Up @@ -843,6 +847,17 @@ static void tcg_out_insn_3313(TCGContext *s, AArch64Insn insn,
| rn << 5 | (rd & 0x1f));
}

static void tcg_out_bti(TCGContext *s, AArch64Insn insn)
{
/*
* While BTI insns are nops on hosts without FEAT_BTI,
* there is no point in emitting them in that case either.
*/
if (cpuinfo & CPUINFO_BTI) {
tcg_out32(s, insn);
}
}

/* Register to register move using ORR (shifted register with no shift). */
static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rm)
{
Expand Down Expand Up @@ -1351,18 +1366,6 @@ static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
tcg_out_insn(s, 3206, B, offset);
}

static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target)
{
ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2;
if (offset == sextract64(offset, 0, 26)) {
tcg_out_insn(s, 3206, B, offset);
} else {
/* Choose X9 as a call-clobbered non-LR temporary. */
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X9, (intptr_t)target);
tcg_out_insn(s, 3207, BR, TCG_REG_X9);
}
}

static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *target)
{
ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2;
Expand Down Expand Up @@ -1947,12 +1950,28 @@ static const tcg_insn_unit *tb_ret_addr;

static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
{
const tcg_insn_unit *target;
ptrdiff_t offset;

/* Reuse the zeroing that exists for goto_ptr. */
if (a0 == 0) {
tcg_out_goto_long(s, tcg_code_gen_epilogue);
target = tcg_code_gen_epilogue;
} else {
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0);
tcg_out_goto_long(s, tb_ret_addr);
target = tb_ret_addr;
}

offset = tcg_pcrel_diff(s, target) >> 2;
if (offset == sextract64(offset, 0, 26)) {
tcg_out_insn(s, 3206, B, offset);
} else {
/*
* Only x16/x17 generate BTI type Jump (2),
* other registers generate BTI type Jump|Call (3).
*/
QEMU_BUILD_BUG_ON(TCG_REG_TMP0 != TCG_REG_X16);
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP0, (intptr_t)target);
tcg_out_insn(s, 3207, BR, TCG_REG_TMP0);
}
}

Expand All @@ -1970,6 +1989,7 @@ static void tcg_out_goto_tb(TCGContext *s, int which)
tcg_out32(s, I3206_B);
tcg_out_insn(s, 3207, BR, TCG_REG_TMP0);
set_jmp_reset_offset(s, which);
tcg_out_bti(s, BTI_J);
}

void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
Expand Down Expand Up @@ -3074,6 +3094,8 @@ static void tcg_target_qemu_prologue(TCGContext *s)
{
TCGReg r;

tcg_out_bti(s, BTI_C);

/* Push (FP, LR) and allocate space for all saved registers. */
tcg_out_insn(s, 3314, STP, TCG_REG_FP, TCG_REG_LR,
TCG_REG_SP, -PUSH_SIZE, 1, 1);
Expand Down Expand Up @@ -3114,10 +3136,12 @@ static void tcg_target_qemu_prologue(TCGContext *s)
* and fall through to the rest of the epilogue.
*/
tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr);
tcg_out_bti(s, BTI_J);
tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_X0, 0);

/* TB epilogue */
tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr);
tcg_out_bti(s, BTI_J);

/* Remove TCG locals stack space. */
tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_SP, TCG_REG_SP,
Expand All @@ -3135,6 +3159,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_insn(s, 3207, RET, TCG_REG_LR);
}

static void tcg_out_tb_start(TCGContext *s)
{
tcg_out_bti(s, BTI_J);
}

static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
{
int i;
Expand Down
7 changes: 6 additions & 1 deletion tcg/arm/tcg-target.c.inc
Expand Up @@ -509,7 +509,7 @@ static bool is_shimm1632(uint32_t v32, int *cmode, int *imm8)
* mov operand2: values represented with x << (2 * y), x < 0x100
* add, sub, eor...: ditto
*/
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -2962,6 +2962,11 @@ static void tcg_out_epilogue(TCGContext *s)
(1 << TCG_REG_R10) | (1 << TCG_REG_R11) | (1 << TCG_REG_PC));
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

typedef struct {
DebugFrameHeader h;
uint8_t fde_def_cfa[4];
Expand Down
7 changes: 6 additions & 1 deletion tcg/i386/tcg-target.c.inc
Expand Up @@ -198,7 +198,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
}

/* test if a constant matches the constraint */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -4191,6 +4191,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_opc(s, OPC_RET, 0, 0, 0);
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
{
memset(p, 0x90, count);
Expand Down
6,251 changes: 6,134 additions & 117 deletions tcg/loongarch64/tcg-insn-defs.c.inc

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions tcg/loongarch64/tcg-target-con-set.h
Expand Up @@ -17,7 +17,11 @@
C_O0_I1(r)
C_O0_I2(rZ, r)
C_O0_I2(rZ, rZ)
C_O0_I2(w, r)
C_O0_I3(r, r, r)
C_O1_I1(r, r)
C_O1_I1(w, r)
C_O1_I1(w, w)
C_O1_I2(r, r, rC)
C_O1_I2(r, r, ri)
C_O1_I2(r, r, rI)
Expand All @@ -29,4 +33,9 @@ C_O1_I2(r, 0, rZ)
C_O1_I2(r, rZ, ri)
C_O1_I2(r, rZ, rJ)
C_O1_I2(r, rZ, rZ)
C_O1_I2(w, w, w)
C_O1_I2(w, w, wM)
C_O1_I2(w, w, wA)
C_O1_I3(w, w, w, w)
C_O1_I4(r, rZ, rJ, rZ, rZ)
C_O2_I1(r, r, r)
3 changes: 3 additions & 0 deletions tcg/loongarch64/tcg-target-con-str.h
Expand Up @@ -14,6 +14,7 @@
* REGS(letter, register_mask)
*/
REGS('r', ALL_GENERAL_REGS)
REGS('w', ALL_VECTOR_REGS)

/*
* Define constraint letters for constants:
Expand All @@ -25,3 +26,5 @@ CONST('U', TCG_CT_CONST_U12)
CONST('Z', TCG_CT_CONST_ZERO)
CONST('C', TCG_CT_CONST_C12)
CONST('W', TCG_CT_CONST_WSZ)
CONST('M', TCG_CT_CONST_VCMP)
CONST('A', TCG_CT_CONST_VADD)
624 changes: 622 additions & 2 deletions tcg/loongarch64/tcg-target.c.inc

Large diffs are not rendered by default.

40 changes: 38 additions & 2 deletions tcg/loongarch64/tcg-target.h
Expand Up @@ -30,7 +30,7 @@
#define LOONGARCH_TCG_TARGET_H

#define TCG_TARGET_INSN_UNIT_SIZE 4
#define TCG_TARGET_NB_REGS 32
#define TCG_TARGET_NB_REGS 64

#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)

Expand Down Expand Up @@ -68,13 +68,25 @@ typedef enum {
TCG_REG_S7,
TCG_REG_S8,

TCG_REG_V0 = 32, TCG_REG_V1, TCG_REG_V2, TCG_REG_V3,
TCG_REG_V4, TCG_REG_V5, TCG_REG_V6, TCG_REG_V7,
TCG_REG_V8, TCG_REG_V9, TCG_REG_V10, TCG_REG_V11,
TCG_REG_V12, TCG_REG_V13, TCG_REG_V14, TCG_REG_V15,
TCG_REG_V16, TCG_REG_V17, TCG_REG_V18, TCG_REG_V19,
TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,

/* aliases */
TCG_AREG0 = TCG_REG_S0,
TCG_REG_TMP0 = TCG_REG_T8,
TCG_REG_TMP1 = TCG_REG_T7,
TCG_REG_TMP2 = TCG_REG_T6,
TCG_VEC_TMP0 = TCG_REG_V23,
} TCGReg;

extern bool use_lsx_instructions;

/* used for function call generation */
#define TCG_REG_CALL_STACK TCG_REG_SP
#define TCG_TARGET_STACK_ALIGN 16
Expand Down Expand Up @@ -159,7 +171,31 @@ typedef enum {
#define TCG_TARGET_HAS_muluh_i64 1
#define TCG_TARGET_HAS_mulsh_i64 1

#define TCG_TARGET_HAS_qemu_ldst_i128 0
#define TCG_TARGET_HAS_qemu_ldst_i128 use_lsx_instructions

#define TCG_TARGET_HAS_v64 0
#define TCG_TARGET_HAS_v128 use_lsx_instructions
#define TCG_TARGET_HAS_v256 0

#define TCG_TARGET_HAS_not_vec 1
#define TCG_TARGET_HAS_neg_vec 1
#define TCG_TARGET_HAS_abs_vec 0
#define TCG_TARGET_HAS_andc_vec 1
#define TCG_TARGET_HAS_orc_vec 1
#define TCG_TARGET_HAS_nand_vec 0
#define TCG_TARGET_HAS_nor_vec 1
#define TCG_TARGET_HAS_eqv_vec 0
#define TCG_TARGET_HAS_mul_vec 1
#define TCG_TARGET_HAS_shi_vec 1
#define TCG_TARGET_HAS_shs_vec 0
#define TCG_TARGET_HAS_shv_vec 1
#define TCG_TARGET_HAS_roti_vec 1
#define TCG_TARGET_HAS_rots_vec 0
#define TCG_TARGET_HAS_rotv_vec 1
#define TCG_TARGET_HAS_sat_vec 1
#define TCG_TARGET_HAS_minmax_vec 1
#define TCG_TARGET_HAS_bitsel_vec 1
#define TCG_TARGET_HAS_cmpsel_vec 0

#define TCG_TARGET_DEFAULT_MO (0)

Expand Down
12 changes: 12 additions & 0 deletions tcg/loongarch64/tcg-target.opc.h
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2023 Jiajie Chen
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version.
*
* See the COPYING file in the top-level directory for details.
*
* Target-specific opcodes for host vector expansion. These will be
* emitted by tcg_expand_vec_op. For those familiar with GCC internals,
* consider these to be UNSPEC with names.
*/
7 changes: 6 additions & 1 deletion tcg/mips/tcg-target.c.inc
Expand Up @@ -190,7 +190,7 @@ static bool is_p2m1(tcg_target_long val)
}

/* test if a constant matches the constraint */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -2628,6 +2628,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_opc_reg(s, OPC_OR, TCG_TMP3, TCG_TMP3, TCG_TMP1);
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

static void tcg_target_init(TCGContext *s)
{
tcg_target_detect_isa();
Expand Down
7 changes: 6 additions & 1 deletion tcg/ppc/tcg-target.c.inc
Expand Up @@ -261,7 +261,7 @@ static bool reloc_pc14(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
}

/* test if a constant matches the constraint */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -2527,6 +2527,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out32(s, BCLR | BO_ALWAYS);
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
{
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, arg);
Expand Down
41 changes: 30 additions & 11 deletions tcg/region.c
Expand Up @@ -33,8 +33,19 @@
#include "tcg/tcg.h"
#include "exec/translation-block.h"
#include "tcg-internal.h"
#include "host/cpuinfo.h"


/*
* Local source-level compatibility with Unix.
* Used by tcg_region_init below.
*/
#if defined(_WIN32)
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#endif

struct tcg_region_tree {
QemuMutex lock;
QTree *tree;
Expand Down Expand Up @@ -83,6 +94,18 @@ bool in_code_gen_buffer(const void *p)
return (size_t)(p - region.start_aligned) <= region.total_size;
}

#ifndef CONFIG_TCG_INTERPRETER
static int host_prot_read_exec(void)
{
#if defined(CONFIG_LINUX) && defined(HOST_AARCH64) && defined(PROT_BTI)
if (cpuinfo & CPUINFO_BTI) {
return PROT_READ | PROT_EXEC | PROT_BTI;
}
#endif
return PROT_READ | PROT_EXEC;
}
#endif

#ifdef CONFIG_DEBUG_TCG
const void *tcg_splitwx_to_rx(void *rw)
{
Expand Down Expand Up @@ -505,14 +528,6 @@ static int alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
return PROT_READ | PROT_WRITE;
}
#elif defined(_WIN32)
/*
* Local source-level compatibility with Unix.
* Used by tcg_region_init below.
*/
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4

static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
{
void *buf;
Expand Down Expand Up @@ -567,7 +582,7 @@ static int alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
goto fail;
}

buf_rx = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
buf_rx = mmap(NULL, size, host_prot_read_exec(), MAP_SHARED, fd, 0);
if (buf_rx == MAP_FAILED) {
goto fail_rx;
}
Expand Down Expand Up @@ -642,7 +657,7 @@ static int alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
return -1;
}

if (mprotect((void *)buf_rx, size, PROT_READ | PROT_EXEC) != 0) {
if (mprotect((void *)buf_rx, size, host_prot_read_exec()) != 0) {
error_setg_errno(errp, errno, "mprotect for jit splitwx");
munmap((void *)buf_rx, size);
munmap((void *)buf_rw, size);
Expand Down Expand Up @@ -805,7 +820,7 @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
need_prot = PROT_READ | PROT_WRITE;
#ifndef CONFIG_TCG_INTERPRETER
if (tcg_splitwx_diff == 0) {
need_prot |= PROT_EXEC;
need_prot |= host_prot_read_exec();
}
#endif
for (size_t i = 0, n = region.n; i < n; i++) {
Expand All @@ -820,7 +835,11 @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
} else if (need_prot == (PROT_READ | PROT_WRITE)) {
rc = qemu_mprotect_rw(start, end - start);
} else {
#ifdef CONFIG_POSIX
rc = mprotect(start, end - start, need_prot);
#else
g_assert_not_reached();
#endif
}
if (rc) {
error_setg_errno(&error_fatal, errno,
Expand Down
7 changes: 6 additions & 1 deletion tcg/riscv/tcg-target.c.inc
Expand Up @@ -145,7 +145,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
#define sextreg sextract64

/* test if a constant matches the constraint */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -2099,6 +2099,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_RA, 0);
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

static volatile sig_atomic_t got_sigill;

static void sigill_handler(int signo, siginfo_t *si, void *data)
Expand Down
7 changes: 6 additions & 1 deletion tcg/s390x/tcg-target.c.inc
Expand Up @@ -540,7 +540,7 @@ static bool risbg_mask(uint64_t c)
}

/* Test if a constant matches the constraint. */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -3483,6 +3483,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
{
memset(p, 0x07, count * sizeof(tcg_insn_unit));
Expand Down
7 changes: 6 additions & 1 deletion tcg/sparc64/tcg-target.c.inc
Expand Up @@ -322,7 +322,7 @@ static bool patch_reloc(tcg_insn_unit *src_rw, int type,
}

/* test if a constant matches the constraint */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
if (ct & TCG_CT_CONST) {
return 1;
Expand Down Expand Up @@ -962,6 +962,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_movi_s13(s, TCG_REG_O0, 0);
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
{
int i;
Expand Down
149 changes: 149 additions & 0 deletions tcg/tcg-op-gvec.c
Expand Up @@ -3846,6 +3846,155 @@ void tcg_gen_gvec_cmp(TCGCond cond, unsigned vece, uint32_t dofs,
}
}

static void expand_cmps_vec(unsigned vece, uint32_t dofs, uint32_t aofs,
uint32_t oprsz, uint32_t tysz, TCGType type,
TCGCond cond, TCGv_vec c)
{
TCGv_vec t0 = tcg_temp_new_vec(type);
TCGv_vec t1 = tcg_temp_new_vec(type);
uint32_t i;

for (i = 0; i < oprsz; i += tysz) {
tcg_gen_ld_vec(t1, cpu_env, aofs + i);
tcg_gen_cmp_vec(cond, vece, t0, t1, c);
tcg_gen_st_vec(t0, cpu_env, dofs + i);
}
}

void tcg_gen_gvec_cmps(TCGCond cond, unsigned vece, uint32_t dofs,
uint32_t aofs, TCGv_i64 c,
uint32_t oprsz, uint32_t maxsz)
{
static const TCGOpcode cmp_list[] = { INDEX_op_cmp_vec, 0 };
static gen_helper_gvec_2i * const eq_fn[4] = {
gen_helper_gvec_eqs8, gen_helper_gvec_eqs16,
gen_helper_gvec_eqs32, gen_helper_gvec_eqs64
};
static gen_helper_gvec_2i * const lt_fn[4] = {
gen_helper_gvec_lts8, gen_helper_gvec_lts16,
gen_helper_gvec_lts32, gen_helper_gvec_lts64
};
static gen_helper_gvec_2i * const le_fn[4] = {
gen_helper_gvec_les8, gen_helper_gvec_les16,
gen_helper_gvec_les32, gen_helper_gvec_les64
};
static gen_helper_gvec_2i * const ltu_fn[4] = {
gen_helper_gvec_ltus8, gen_helper_gvec_ltus16,
gen_helper_gvec_ltus32, gen_helper_gvec_ltus64
};
static gen_helper_gvec_2i * const leu_fn[4] = {
gen_helper_gvec_leus8, gen_helper_gvec_leus16,
gen_helper_gvec_leus32, gen_helper_gvec_leus64
};
static gen_helper_gvec_2i * const * const fns[16] = {
[TCG_COND_EQ] = eq_fn,
[TCG_COND_LT] = lt_fn,
[TCG_COND_LE] = le_fn,
[TCG_COND_LTU] = ltu_fn,
[TCG_COND_LEU] = leu_fn,
};

TCGType type;

check_size_align(oprsz, maxsz, dofs | aofs);
check_overlap_2(dofs, aofs, maxsz);

if (cond == TCG_COND_NEVER || cond == TCG_COND_ALWAYS) {
do_dup(MO_8, dofs, oprsz, maxsz,
NULL, NULL, -(cond == TCG_COND_ALWAYS));
return;
}

/*
* Implement inline with a vector type, if possible.
* Prefer integer when 64-bit host and 64-bit comparison.
*/
type = choose_vector_type(cmp_list, vece, oprsz,
TCG_TARGET_REG_BITS == 64 && vece == MO_64);
if (type != 0) {
const TCGOpcode *hold_list = tcg_swap_vecop_list(cmp_list);
TCGv_vec t_vec = tcg_temp_new_vec(type);
uint32_t some;

tcg_gen_dup_i64_vec(vece, t_vec, c);
switch (type) {
case TCG_TYPE_V256:
some = QEMU_ALIGN_DOWN(oprsz, 32);
expand_cmps_vec(vece, dofs, aofs, some, 32,
TCG_TYPE_V256, cond, t_vec);
aofs += some;
dofs += some;
oprsz -= some;
maxsz -= some;
/* fallthru */

case TCG_TYPE_V128:
some = QEMU_ALIGN_DOWN(oprsz, 16);
expand_cmps_vec(vece, dofs, aofs, some, 16,
TCG_TYPE_V128, cond, t_vec);
break;

case TCG_TYPE_V64:
some = QEMU_ALIGN_DOWN(oprsz, 8);
expand_cmps_vec(vece, dofs, aofs, some, 8,
TCG_TYPE_V64, cond, t_vec);
break;

default:
g_assert_not_reached();
}
tcg_temp_free_vec(t_vec);
tcg_swap_vecop_list(hold_list);
} else if (vece == MO_64 && check_size_impl(oprsz, 8)) {
TCGv_i64 t0 = tcg_temp_ebb_new_i64();
uint32_t i;

for (i = 0; i < oprsz; i += 8) {
tcg_gen_ld_i64(t0, cpu_env, aofs + i);
tcg_gen_negsetcond_i64(cond, t0, t0, c);
tcg_gen_st_i64(t0, cpu_env, dofs + i);
}
tcg_temp_free_i64(t0);
} else if (vece == MO_32 && check_size_impl(oprsz, 4)) {
TCGv_i32 t0 = tcg_temp_ebb_new_i32();
TCGv_i32 t1 = tcg_temp_ebb_new_i32();
uint32_t i;

tcg_gen_extrl_i64_i32(t1, c);
for (i = 0; i < oprsz; i += 8) {
tcg_gen_ld_i32(t0, cpu_env, aofs + i);
tcg_gen_negsetcond_i32(cond, t0, t0, t1);
tcg_gen_st_i32(t0, cpu_env, dofs + i);
}
tcg_temp_free_i32(t0);
tcg_temp_free_i32(t1);
} else {
gen_helper_gvec_2i * const *fn = fns[cond];
bool inv = false;

if (fn == NULL) {
cond = tcg_invert_cond(cond);
fn = fns[cond];
assert(fn != NULL);
inv = true;
}
tcg_gen_gvec_2i_ool(dofs, aofs, c, oprsz, maxsz, inv, fn[vece]);
return;
}

if (oprsz < maxsz) {
expand_clr(dofs + oprsz, maxsz - oprsz);
}
}

void tcg_gen_gvec_cmpi(TCGCond cond, unsigned vece, uint32_t dofs,
uint32_t aofs, int64_t c,
uint32_t oprsz, uint32_t maxsz)
{
TCGv_i64 tmp = tcg_constant_i64(c);
tcg_gen_gvec_cmps(cond, vece, dofs, aofs, tmp, oprsz, maxsz);
}

static void tcg_gen_bitsel_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, TCGv_i64 c)
{
TCGv_i64 t = tcg_temp_ebb_new_i64();
Expand Down
7 changes: 5 additions & 2 deletions tcg/tcg.c
Expand Up @@ -108,6 +108,7 @@ static void tcg_register_jit_int(const void *buf, size_t size,
__attribute__((unused));

/* Forward declarations for functions declared and used in tcg-target.c.inc. */
static void tcg_out_tb_start(TCGContext *s);
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
intptr_t arg2);
static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
Expand Down Expand Up @@ -171,7 +172,7 @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
const TCGHelperInfo *info);
static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot);
static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece);
#ifdef TCG_TARGET_NEED_LDST_LABELS
static int tcg_out_ldst_finalize(TCGContext *s);
#endif
Expand Down Expand Up @@ -4689,7 +4690,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
ts = arg_temp(arg);

if (ts->val_type == TEMP_VAL_CONST
&& tcg_target_const_match(ts->val, ts->type, arg_ct->ct)) {
&& tcg_target_const_match(ts->val, ts->type, arg_ct->ct, TCGOP_VECE(op))) {
/* constant is OK for instruction */
const_args[i] = 1;
new_args[i] = ts->val;
Expand Down Expand Up @@ -6014,6 +6015,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
s->gen_insn_data =
tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words);

tcg_out_tb_start(s);

num_insns = -1;
QTAILQ_FOREACH(op, &s->ops, link) {
TCGOpcode opc = op->opc;
Expand Down
7 changes: 6 additions & 1 deletion tcg/tci/tcg-target.c.inc
Expand Up @@ -913,7 +913,7 @@ static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
}

/* Test if a constant matches the constraint. */
static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
{
return ct & TCG_CT_CONST;
}
Expand Down Expand Up @@ -955,6 +955,11 @@ static inline void tcg_target_qemu_prologue(TCGContext *s)
{
}

static void tcg_out_tb_start(TCGContext *s)
{
/* nothing to do */
}

bool tcg_target_has_memory_bswap(MemOp memop)
{
return true;
Expand Down
Binary file modified tests/data/acpi/virt/SSDT.memhp
Binary file not shown.
1 change: 1 addition & 0 deletions tests/docker/dockerfiles/alpine.docker
Expand Up @@ -59,6 +59,7 @@ RUN apk update && \
libtasn1-dev \
liburing-dev \
libusb-dev \
libxdp-dev \
linux-pam-dev \
llvm \
lttng-ust-dev \
Expand Down
1 change: 1 addition & 0 deletions tests/docker/dockerfiles/centos8.docker
Expand Up @@ -75,6 +75,7 @@ RUN dnf distro-sync -y && \
libubsan \
liburing-devel \
libusbx-devel \
libxdp-devel \
libzstd-devel \
llvm \
lttng-ust-devel \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/debian-amd64-cross.docker
Expand Up @@ -84,7 +84,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
g++-x86-64-linux-gnu \
gcc-x86-64-linux-gnu \
libaio-dev:amd64 \
libasan5:amd64 \
libasan6:amd64 \
libasound2-dev:amd64 \
libattr1-dev:amd64 \
libbpf-dev:amd64 \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/debian-amd64.docker
Expand Up @@ -32,7 +32,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libaio-dev \
libasan5 \
libasan6 \
libasound2-dev \
libattr1-dev \
libbpf-dev \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/debian-arm64-cross.docker
Expand Up @@ -84,7 +84,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
g++-aarch64-linux-gnu \
gcc-aarch64-linux-gnu \
libaio-dev:arm64 \
libasan5:arm64 \
libasan6:arm64 \
libasound2-dev:arm64 \
libattr1-dev:arm64 \
libbpf-dev:arm64 \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/debian-armel-cross.docker
Expand Up @@ -84,7 +84,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
g++-arm-linux-gnueabi \
gcc-arm-linux-gnueabi \
libaio-dev:armel \
libasan5:armel \
libasan6:armel \
libasound2-dev:armel \
libattr1-dev:armel \
libbpf-dev:armel \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/debian-armhf-cross.docker
Expand Up @@ -84,7 +84,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
g++-arm-linux-gnueabihf \
gcc-arm-linux-gnueabihf \
libaio-dev:armhf \
libasan5:armhf \
libasan6:armhf \
libasound2-dev:armhf \
libattr1-dev:armhf \
libbpf-dev:armhf \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/debian-ppc64el-cross.docker
Expand Up @@ -84,7 +84,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
g++-powerpc64le-linux-gnu \
gcc-powerpc64le-linux-gnu \
libaio-dev:ppc64el \
libasan5:ppc64el \
libasan6:ppc64el \
libasound2-dev:ppc64el \
libattr1-dev:ppc64el \
libbpf-dev:ppc64el \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/debian-s390x-cross.docker
Expand Up @@ -84,7 +84,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
g++-s390x-linux-gnu \
gcc-s390x-linux-gnu \
libaio-dev:s390x \
libasan5:s390x \
libasan6:s390x \
libasound2-dev:s390x \
libattr1-dev:s390x \
libbpf-dev:s390x \
Expand Down
1 change: 1 addition & 0 deletions tests/docker/dockerfiles/fedora.docker
Expand Up @@ -82,6 +82,7 @@ exec "$@"\n' > /usr/bin/nosync && \
libubsan \
liburing-devel \
libusbx-devel \
libxdp-devel \
libzstd-devel \
llvm \
lttng-ust-devel \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/opensuse-leap.docker
Expand Up @@ -40,7 +40,7 @@ RUN zypper update -y && \
libSDL2-devel \
libSDL2_image-devel \
libaio-devel \
libasan6 \
libasan8 \
libattr-devel \
libbpf-devel \
libbz2-devel \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/ubuntu2004.docker
Expand Up @@ -32,7 +32,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libaio-dev \
libasan5 \
libasan6 \
libasound2-dev \
libattr1-dev \
libbrlapi-dev \
Expand Down
2 changes: 1 addition & 1 deletion tests/docker/dockerfiles/ubuntu2204.docker
Expand Up @@ -32,7 +32,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libaio-dev \
libasan5 \
libasan6 \
libasound2-dev \
libattr1-dev \
libbpf-dev \
Expand Down
2 changes: 1 addition & 1 deletion tests/lcitool/libvirt-ci
Submodule libvirt-ci updated from bbd55b to 5f84a2
1 change: 1 addition & 0 deletions tests/lcitool/projects/qemu.yml
Expand Up @@ -69,6 +69,7 @@ packages:
- liburing
- libusbx
- libvdeplug
- libxdp
- libzstd
- llvm
- lttng-ust
Expand Down
5 changes: 5 additions & 0 deletions tests/qtest/libqos/igb.c
Expand Up @@ -109,6 +109,11 @@ static void igb_pci_start_hw(QOSGraphObject *obj)
E1000_RAH_AV | E1000_RAH_POOL_1 |
le16_to_cpu(*(uint16_t *)(address + 4)));

/* Set supported receive descriptor mode */
e1000e_macreg_write(&d->e1000e,
E1000_SRRCTL(0),
E1000_SRRCTL_DESCTYPE_ADV_ONEBUF);

/* Enable receive */
e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN);
e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN);
Expand Down
2 changes: 1 addition & 1 deletion tests/tcg/m68k/Makefile.target
Expand Up @@ -4,7 +4,7 @@
#

VPATH += $(SRC_PATH)/tests/tcg/m68k
TESTS += trap
TESTS += trap denormal

# On m68k Linux supports 4k and 8k pages (but 8k is currently broken)
EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-8192
53 changes: 53 additions & 0 deletions tests/tcg/m68k/denormal.c
@@ -0,0 +1,53 @@
/*
* Test m68k extended double denormals.
*/

#include <stdio.h>
#include <stdint.h>

#define TEST(X, Y) { X, Y, X * Y }

static volatile long double test[][3] = {
TEST(0x1p+16383l, 0x1p-16446l),
TEST(0x1.1p-8223l, 0x1.1p-8224l),
TEST(1.0l, 0x1p-16383l),
};

#undef TEST

static void dump_ld(const char *label, long double ld)
{
union {
long double d;
struct {
uint32_t exp:16;
uint32_t space:16;
uint32_t h;
uint32_t l;
};
} u;

u.d = ld;
printf("%12s: % -27La 0x%04x 0x%08x 0x%08x\n", label, u.d, u.exp, u.h, u.l);
}

int main(void)
{
int i, n = sizeof(test) / sizeof(test[0]), err = 0;

for (i = 0; i < n; ++i) {
long double x = test[i][0];
long double y = test[i][1];
long double build_mul = test[i][2];
long double runtime_mul = x * y;

if (runtime_mul != build_mul) {
dump_ld("x", x);
dump_ld("y", y);
dump_ld("build_mul", build_mul);
dump_ld("runtime_mul", runtime_mul);
err = 1;
}
}
return err;
}
7 changes: 7 additions & 0 deletions util/cpuinfo-aarch64.c
Expand Up @@ -13,6 +13,9 @@
# include <asm/hwcap.h>
# include "elf.h"
# endif
# ifndef HWCAP2_BTI
# define HWCAP2_BTI 0 /* added in glibc 2.32 */
# endif
#endif
#ifdef CONFIG_DARWIN
# include <sys/sysctl.h>
Expand Down Expand Up @@ -58,12 +61,16 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
info |= (hwcap & HWCAP_USCAT ? CPUINFO_LSE2 : 0);
info |= (hwcap & HWCAP_AES ? CPUINFO_AES : 0);
info |= (hwcap & HWCAP_PMULL ? CPUINFO_PMULL : 0);

unsigned long hwcap2 = qemu_getauxval(AT_HWCAP2);
info |= (hwcap2 & HWCAP2_BTI ? CPUINFO_BTI : 0);
#endif
#ifdef CONFIG_DARWIN
info |= sysctl_for_bool("hw.optional.arm.FEAT_LSE") * CPUINFO_LSE;
info |= sysctl_for_bool("hw.optional.arm.FEAT_LSE2") * CPUINFO_LSE2;
info |= sysctl_for_bool("hw.optional.arm.FEAT_AES") * CPUINFO_AES;
info |= sysctl_for_bool("hw.optional.arm.FEAT_PMULL") * CPUINFO_PMULL;
info |= sysctl_for_bool("hw.optional.arm.FEAT_BTI") * CPUINFO_BTI;
#endif

cpuinfo = info;
Expand Down
15 changes: 3 additions & 12 deletions util/oslib-posix.c
Expand Up @@ -585,7 +585,7 @@ char *qemu_get_pid_name(pid_t pid)

void *qemu_alloc_stack(size_t *sz)
{
void *ptr, *guardpage;
void *ptr;
int flags;
#ifdef CONFIG_DEBUG_STACK_USAGE
void *ptr2;
Expand Down Expand Up @@ -618,17 +618,8 @@ void *qemu_alloc_stack(size_t *sz)
abort();
}

#if defined(HOST_IA64)
/* separate register stack */
guardpage = ptr + (((*sz - pagesz) / 2) & ~pagesz);
#elif defined(HOST_HPPA)
/* stack grows up */
guardpage = ptr + *sz - pagesz;
#else
/* stack grows down */
guardpage = ptr;
#endif
if (mprotect(guardpage, pagesz, PROT_NONE) != 0) {
/* Stack grows down -- guard page at the bottom. */
if (mprotect(ptr, pagesz, PROT_NONE) != 0) {
perror("failed to set up stack guard page");
abort();
}
Expand Down